summaryrefslogtreecommitdiff
path: root/arch/powerpc/cpu/mpc8xx
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/cpu/mpc8xx')
-rw-r--r--arch/powerpc/cpu/mpc8xx/Makefile66
-rw-r--r--arch/powerpc/cpu/mpc8xx/bedbug_860.c316
-rw-r--r--arch/powerpc/cpu/mpc8xx/commproc.c131
-rw-r--r--arch/powerpc/cpu/mpc8xx/config.mk26
-rw-r--r--arch/powerpc/cpu/mpc8xx/cpu.c654
-rw-r--r--arch/powerpc/cpu/mpc8xx/cpu_init.c285
-rw-r--r--arch/powerpc/cpu/mpc8xx/fdt.c46
-rw-r--r--arch/powerpc/cpu/mpc8xx/fec.c1026
-rw-r--r--arch/powerpc/cpu/mpc8xx/fec.h28
-rw-r--r--arch/powerpc/cpu/mpc8xx/i2c.c707
-rw-r--r--arch/powerpc/cpu/mpc8xx/interrupts.c294
-rw-r--r--arch/powerpc/cpu/mpc8xx/kgdb.S74
-rw-r--r--arch/powerpc/cpu/mpc8xx/lcd.c621
-rw-r--r--arch/powerpc/cpu/mpc8xx/plprcr_write.S135
-rw-r--r--arch/powerpc/cpu/mpc8xx/scc.c572
-rw-r--r--arch/powerpc/cpu/mpc8xx/serial.c745
-rw-r--r--arch/powerpc/cpu/mpc8xx/speed.c416
-rw-r--r--arch/powerpc/cpu/mpc8xx/spi.c560
-rw-r--r--arch/powerpc/cpu/mpc8xx/start.S684
-rw-r--r--arch/powerpc/cpu/mpc8xx/traps.c241
-rw-r--r--arch/powerpc/cpu/mpc8xx/upatch.c194
-rw-r--r--arch/powerpc/cpu/mpc8xx/video.c1331
-rw-r--r--arch/powerpc/cpu/mpc8xx/wlkbd.c36
23 files changed, 9188 insertions, 0 deletions
diff --git a/arch/powerpc/cpu/mpc8xx/Makefile b/arch/powerpc/cpu/mpc8xx/Makefile
new file mode 100644
index 0000000..5f70459
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/Makefile
@@ -0,0 +1,66 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+# CFLAGS += -DET_DEBUG
+
+LIB = $(obj)lib$(CPU).a
+
+START-y += start.o
+START-y += kgdb.o
+COBJS-y += bedbug_860.o
+COBJS-y += commproc.o
+COBJS-y += cpu.o
+COBJS-y += cpu_init.o
+COBJS-y += fec.o
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+COBJS-y += i2c.o
+COBJS-y += interrupts.o
+COBJS-y += lcd.o
+COBJS-y += scc.o
+COBJS-y += serial.o
+COBJS-y += speed.o
+COBJS-y += spi.o
+COBJS-y += traps.o
+COBJS-y += upatch.o
+COBJS-y += video.o
+SOBJS-y += plprcr_write.o
+
+SRCS := $(START-y:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+START := $(addprefix $(obj),$(START-y))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS) $(obj)kgdb.o
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc8xx/bedbug_860.c b/arch/powerpc/cpu/mpc8xx/bedbug_860.c
new file mode 100644
index 0000000..0308bbb
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/bedbug_860.c
@@ -0,0 +1,316 @@
+/*
+ * Bedbug Functions specific to the MPC860 chip
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <bedbug/bedbug.h>
+#include <bedbug/regs.h>
+#include <bedbug/ppc.h>
+#include <bedbug/type.h>
+
+#if defined(CONFIG_CMD_BEDBUG) && defined(CONFIG_8xx)
+
+#define MAX_BREAK_POINTS 2
+
+extern CPU_DEBUG_CTX bug_ctx;
+
+void bedbug860_init __P((void));
+void bedbug860_do_break __P((cmd_tbl_t*,int,int,char*[]));
+void bedbug860_break_isr __P((struct pt_regs*));
+int bedbug860_find_empty __P((void));
+int bedbug860_set __P((int,unsigned long));
+int bedbug860_clear __P((int));
+
+
+/* ======================================================================
+ * Initialize the global bug_ctx structure for the MPC860. Clear all
+ * of the breakpoints.
+ * ====================================================================== */
+
+void bedbug860_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 = bedbug860_do_break;
+ bug_ctx.break_isr = bedbug860_break_isr;
+ bug_ctx.find_empty = bedbug860_find_empty;
+ bug_ctx.set = bedbug860_set;
+ bug_ctx.clear = bedbug860_clear;
+
+ for( i = 1; i <= MAX_BREAK_POINTS; ++i )
+ (*bug_ctx.clear)( i );
+
+ puts ("BEDBUG:ready\n");
+ return;
+} /* bedbug_init_breakpoints */
+
+
+
+/* ======================================================================
+ * Set/clear/show one of the hardware breakpoints for the 860. 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 bedbug860_do_break (cmd_tbl_t *cmdtp, int flag, int argc,
+ char *argv[])
+{
+ long addr = 0; /* 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 )
+ {
+ printf( "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 )
+ {
+
+ switch( which_bp )
+ {
+ case 1: addr = GET_CMPA(); break;
+ case 2: addr = GET_CMPB(); break;
+ case 3: addr = GET_CMPC(); break;
+ case 4: addr = GET_CMPD(); break;
+ }
+
+ printf( "Breakpoint [%d]: ", which_bp );
+ if( addr == 0 )
+ printf( "NOT SET\n" );
+ else
+ disppc( (unsigned char *)addr, 0, 1, bedbug_puts, F_RADHEX );
+ }
+ return;
+ }
+
+ /* Set a breakpoint at the address */
+
+ if( !isdigit( argv[ 1 ][ 0 ]))
+ {
+ cmd_usage(cmdtp);
+ return;
+ }
+
+ addr = simple_strtoul( argv[ 1 ], NULL, 16 ) & 0xfffffffc;
+
+ 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;
+} /* bedbug860_do_break */
+
+
+
+/* ======================================================================
+ * Handle a breakpoint. First determine which breakpoint was hit by
+ * looking at the DeBug Status Register (DBSR), clear the breakpoint
+ * and enter a mini main loop. Stay in the loop until the stopped flag
+ * in the debug context is cleared.
+ * ====================================================================== */
+
+void bedbug860_break_isr( struct pt_regs *regs )
+{
+ unsigned long addr; /* Address stopped at */
+ unsigned long cause; /* Address stopped at */
+ /* -------------------------------------------------- */
+
+ cause = GET_ICR();
+
+ if( !(cause & 0x00000004)) {
+ printf( "Not an instruction breakpoint (ICR 0x%08lx)\n", cause );
+ return;
+ }
+
+ addr = regs->nip;
+
+ if( addr == GET_CMPA() )
+ {
+ bug_ctx.current_bp = 1;
+ }
+ else if( addr == GET_CMPB() )
+ {
+ bug_ctx.current_bp = 2;
+ }
+ else if( addr == GET_CMPC() )
+ {
+ bug_ctx.current_bp = 3;
+ }
+ else if( addr == GET_CMPD() )
+ {
+ bug_ctx.current_bp = 4;
+ }
+
+ bedbug_main_loop( addr, regs );
+ return;
+} /* bedbug860_break_isr */
+
+
+
+/* ======================================================================
+ * Look through all of the hardware breakpoints available to see if one
+ * is unused.
+ * ====================================================================== */
+
+int bedbug860_find_empty( void )
+{
+ /* -------------------------------------------------- */
+
+ if( GET_CMPA() == 0 )
+ return 1;
+
+ if( GET_CMPB() == 0 )
+ return 2;
+
+ if( GET_CMPC() == 0 )
+ return 3;
+
+ if( GET_CMPD() == 0 )
+ return 4;
+
+ return 0;
+} /* bedbug860_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 appropriate IACx register and enable proper address
+ * beakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug860_set( int which_bp, unsigned long addr )
+{
+ /* -------------------------------------------------- */
+
+ /* Only look if which_bp == 0, else use which_bp */
+ if(( bug_ctx.find_empty ) && ( !which_bp ) &&
+ ( which_bp = (*bug_ctx.find_empty)()) == 0 )
+ {
+ printf( "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_DER( GET_DER() | 0x00000004 );
+ }
+
+ switch( which_bp )
+ {
+ case 1:
+ SET_CMPA( addr );
+ SET_ICTRL( GET_ICTRL() | 0x80080800 ); /* CTA=Equal,IW0=Match A,SIW0EN */
+ break;
+
+ case 2:
+ SET_CMPB( addr );
+ SET_ICTRL( GET_ICTRL() | 0x10020400 ); /* CTB=Equal,IW1=Match B,SIW1EN */
+ break;
+
+ case 3:
+ SET_CMPC( addr );
+ SET_ICTRL( GET_ICTRL() | 0x02008200 ); /* CTC=Equal,IW2=Match C,SIW2EN */
+ break;
+
+ case 4:
+ SET_CMPD( addr );
+ SET_ICTRL( GET_ICTRL() | 0x00404100 ); /* CTD=Equal,IW3=Match D,SIW3EN */
+ break;
+ }
+
+ return which_bp;
+} /* bedbug860_set */
+
+
+
+/* ======================================================================
+ * Disable a specific breakoint by setting the appropriate IACx register
+ * to zero and claring the instruction address breakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug860_clear( int which_bp )
+{
+ /* -------------------------------------------------- */
+
+ if( which_bp < 1 || which_bp > MAX_BREAK_POINTS )
+ {
+ printf( "Invalid break point # (%d)\n", which_bp );
+ return -1;
+ }
+
+ switch( which_bp )
+ {
+ case 1:
+ SET_CMPA( 0 );
+ SET_ICTRL( GET_ICTRL() & ~0x80080800 ); /* CTA=Equal,IW0=Match A,SIW0EN */
+ break;
+
+ case 2:
+ SET_CMPB( 0 );
+ SET_ICTRL( GET_ICTRL() & ~0x10020400 ); /* CTB=Equal,IW1=Match B,SIW1EN */
+ break;
+
+ case 3:
+ SET_CMPC( 0 );
+ SET_ICTRL( GET_ICTRL() & ~0x02008200 ); /* CTC=Equal,IW2=Match C,SIW2EN */
+ break;
+
+ case 4:
+ SET_CMPD( 0 );
+ SET_ICTRL( GET_ICTRL() & ~0x00404100 ); /* CTD=Equal,IW3=Match D,SIW3EN */
+ break;
+ }
+
+ return 0;
+} /* bedbug860_clear */
+
+
+/* ====================================================================== */
+#endif
diff --git a/arch/powerpc/cpu/mpc8xx/commproc.c b/arch/powerpc/cpu/mpc8xx/commproc.c
new file mode 100644
index 0000000..a87a0dc
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/commproc.c
@@ -0,0 +1,131 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <commproc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+
+int dpram_init (void)
+{
+ /* Reclaim the DP memory for our use. */
+ gd->dp_alloc_base = CPM_DATAONLY_BASE;
+ gd->dp_alloc_top = CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE;
+
+ return (0);
+}
+
+/* Allocate some memory from the dual ported ram. We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint dpram_alloc (uint size)
+{
+ uint addr = gd->dp_alloc_base;
+
+ if ((gd->dp_alloc_base + size) >= gd->dp_alloc_top)
+ return (CPM_DP_NOSPACE);
+
+ gd->dp_alloc_base += size;
+
+ return addr;
+}
+
+uint dpram_base (void)
+{
+ return gd->dp_alloc_base;
+}
+
+/* Allocate some memory from the dual ported ram. We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint dpram_alloc_align (uint size, uint align)
+{
+ uint addr, mask = align - 1;
+
+ addr = (gd->dp_alloc_base + mask) & ~mask;
+
+ if ((addr + size) >= gd->dp_alloc_top)
+ return (CPM_DP_NOSPACE);
+
+ gd->dp_alloc_base = addr + size;
+
+ return addr;
+}
+
+uint dpram_base_align (uint align)
+{
+ uint mask = align - 1;
+
+ return (gd->dp_alloc_base + mask) & ~mask;
+}
+#endif /* CONFIG_SYS_ALLOC_DPRAM */
+
+#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
+
+void post_word_store (ulong a)
+{
+ volatile void *save_addr =
+ ((immap_t *) CONFIG_SYS_IMMR)->im_cpm.cp_dpmem + CPM_POST_WORD_ADDR;
+
+ *(volatile ulong *) save_addr = a;
+}
+
+ulong post_word_load (void)
+{
+ volatile void *save_addr =
+ ((immap_t *) CONFIG_SYS_IMMR)->im_cpm.cp_dpmem + CPM_POST_WORD_ADDR;
+
+ return *(volatile ulong *) save_addr;
+}
+
+#endif /* CONFIG_POST || CONFIG_LOGBUFFER*/
+
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+
+void bootcount_store (ulong a)
+{
+ volatile ulong *save_addr =
+ (volatile ulong *)( ((immap_t *) CONFIG_SYS_IMMR)->im_cpm.cp_dpmem +
+ CPM_BOOTCOUNT_ADDR );
+
+ save_addr[0] = a;
+ save_addr[1] = BOOTCOUNT_MAGIC;
+}
+
+ulong bootcount_load (void)
+{
+ volatile ulong *save_addr =
+ (volatile ulong *)( ((immap_t *) CONFIG_SYS_IMMR)->im_cpm.cp_dpmem +
+ CPM_BOOTCOUNT_ADDR );
+
+ if (save_addr[1] != BOOTCOUNT_MAGIC)
+ return 0;
+ else
+ return save_addr[0];
+}
+
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
diff --git a/arch/powerpc/cpu/mpc8xx/config.mk b/arch/powerpc/cpu/mpc8xx/config.mk
new file mode 100644
index 0000000..5540d65
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/config.mk
@@ -0,0 +1,26 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -fPIC -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_8xx -ffixed-r2 -mstring -mcpu=860 -msoft-float
diff --git a/arch/powerpc/cpu/mpc8xx/cpu.c b/arch/powerpc/cpu/mpc8xx/cpu.c
new file mode 100644
index 0000000..2eb848b
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/cpu.c
@@ -0,0 +1,654 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * m8xx.c
+ *
+ * CPU specific code
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * minor modifications by
+ * Wolfgang Denk <wd@denx.de>
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc8xx.h>
+#include <commproc.h>
+#include <netdev.h>
+#include <asm/cache.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <libfdt_env.h>
+#include <fdt_support.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static char *cpu_warning = "\n " \
+ "*** Warning: CPU Core has Silicon Bugs -- Check the Errata ***";
+
+#if ((defined(CONFIG_MPC86x) || defined(CONFIG_MPC855)) && \
+ !defined(CONFIG_MPC862))
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+ char *id_str =
+# if defined(CONFIG_MPC855)
+ "PC855";
+# elif defined(CONFIG_MPC860P)
+ "PC860P";
+# else
+ NULL;
+# endif
+ volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+ uint k, m;
+ char buf[32];
+ char pre = 'X';
+ char *mid = "xx";
+ char *suf;
+
+ /* the highest 16 bits should be 0x0050 for a 860 */
+
+ if ((pvr >> 16) != 0x0050)
+ return -1;
+
+ k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
+ m = 0;
+ suf = "";
+
+ /*
+ * Some boards use sockets so different CPUs can be used.
+ * We have to check chip version in run time.
+ */
+ switch (k) {
+ case 0x00020001: pre = 'P'; break;
+ case 0x00030001: break;
+ case 0x00120003: suf = "A"; break;
+ case 0x00130003: suf = "A3"; break;
+
+ case 0x00200004: suf = "B"; break;
+
+ case 0x00300004: suf = "C"; break;
+ case 0x00310004: suf = "C1"; m = 1; break;
+
+ case 0x00200064: mid = "SR"; suf = "B"; break;
+ case 0x00300065: mid = "SR"; suf = "C"; break;
+ case 0x00310065: mid = "SR"; suf = "C1"; m = 1; break;
+ case 0x05010000: suf = "D3"; m = 1; break;
+ case 0x05020000: suf = "D4"; m = 1; break;
+ /* this value is not documented anywhere */
+ case 0x40000000: pre = 'P'; suf = "D"; m = 1; break;
+ /* MPC866P/MPC866T/MPC859T/MPC859DSL/MPC852T */
+ case 0x08010004: /* Rev. A.0 */
+ suf = "A";
+ /* fall through */
+ case 0x08000003: /* Rev. 0.3 */
+ pre = 'M'; m = 1;
+ if (id_str == NULL)
+ id_str =
+# if defined(CONFIG_MPC852T)
+ "PC852T";
+# elif defined(CONFIG_MPC859T)
+ "PC859T";
+# elif defined(CONFIG_MPC859DSL)
+ "PC859DSL";
+# elif defined(CONFIG_MPC866T)
+ "PC866T";
+# else
+ "PC866x"; /* Unknown chip from MPC866 family */
+# endif
+ break;
+ case 0x09000000: pre = 'M'; mid = suf = ""; m = 1;
+ if (id_str == NULL)
+ id_str = "PC885"; /* 870/875/880/885 */
+ break;
+
+ default: suf = NULL; break;
+ }
+
+ if (id_str == NULL)
+ id_str = "PC86x"; /* Unknown 86x chip */
+ if (suf)
+ printf ("%c%s%sZPnn%s", pre, id_str, mid, suf);
+ else
+ printf ("unknown M%s (0x%08x)", id_str, k);
+
+
+#if defined(CONFIG_SYS_8xx_CPUCLK_MIN) && defined(CONFIG_SYS_8xx_CPUCLK_MAX)
+ printf (" at %s MHz [%d.%d...%d.%d MHz]\n ",
+ strmhz (buf, clock),
+ CONFIG_SYS_8xx_CPUCLK_MIN / 1000000,
+ ((CONFIG_SYS_8xx_CPUCLK_MIN % 1000000) + 50000) / 100000,
+ CONFIG_SYS_8xx_CPUCLK_MAX / 1000000,
+ ((CONFIG_SYS_8xx_CPUCLK_MAX % 1000000) + 50000) / 100000
+ );
+#else
+ printf (" at %s MHz: ", strmhz (buf, clock));
+#endif
+ printf ("%u kB I-Cache %u kB D-Cache",
+ checkicache () >> 10,
+ checkdcache () >> 10
+ );
+
+ /* do we have a FEC (860T/P or 852/859/866/885)? */
+
+ immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+ if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+ printf (" FEC present");
+ }
+
+ if (!m) {
+ puts (cpu_warning);
+ }
+
+ putc ('\n');
+
+#ifdef DEBUG
+ if(clock != measure_gclk()) {
+ printf ("clock %ldHz != %dHz\n", clock, measure_gclk());
+ }
+#endif
+
+ return 0;
+}
+
+#elif defined(CONFIG_MPC862)
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+ volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+ uint k, m;
+ char buf[32];
+ char pre = 'X';
+ char *mid = "xx";
+ char *suf;
+
+ /* the highest 16 bits should be 0x0050 for a 8xx */
+
+ if ((pvr >> 16) != 0x0050)
+ return -1;
+
+ k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
+ m = 0;
+
+ switch (k) {
+
+ /* this value is not documented anywhere */
+ case 0x06000000: mid = "P"; suf = "0"; break;
+ case 0x06010001: mid = "P"; suf = "A"; m = 1; break;
+ case 0x07000003: mid = "P"; suf = "B"; m = 1; break;
+ default: suf = NULL; break;
+ }
+
+#ifndef CONFIG_MPC857
+ if (suf)
+ printf ("%cPC862%sZPnn%s", pre, mid, suf);
+ else
+ printf ("unknown MPC862 (0x%08x)", k);
+#else
+ if (suf)
+ printf ("%cPC857TZPnn%s", pre, suf); /* only 857T tested right now! */
+ else
+ printf ("unknown MPC857 (0x%08x)", k);
+#endif
+
+ printf (" at %s MHz:", strmhz (buf, clock));
+
+ printf (" %u kB I-Cache", checkicache () >> 10);
+ printf (" %u kB D-Cache", checkdcache () >> 10);
+
+ /* lets check and see if we're running on a 862T (or P?) */
+
+ immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+ if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+ printf (" FEC present");
+ }
+
+ if (!m) {
+ puts (cpu_warning);
+ }
+
+ putc ('\n');
+
+ return 0;
+}
+
+#elif defined(CONFIG_MPC823)
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+ volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+ uint k, m;
+ char buf[32];
+ char *suf;
+
+ /* the highest 16 bits should be 0x0050 for a 8xx */
+
+ if ((pvr >> 16) != 0x0050)
+ return -1;
+
+ k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
+ m = 0;
+
+ switch (k) {
+ /* MPC823 */
+ case 0x20000000: suf = "0"; break;
+ case 0x20010000: suf = "0.1"; break;
+ case 0x20020000: suf = "Z2/3"; break;
+ case 0x20020001: suf = "Z3"; break;
+ case 0x21000000: suf = "A"; break;
+ case 0x21010000: suf = "B"; m = 1; break;
+ case 0x21010001: suf = "B2"; m = 1; break;
+ /* MPC823E */
+ case 0x24010000: suf = NULL;
+ puts ("PPC823EZTnnB2");
+ m = 1;
+ break;
+ default:
+ suf = NULL;
+ printf ("unknown MPC823 (0x%08x)", k);
+ break;
+ }
+ if (suf)
+ printf ("PPC823ZTnn%s", suf);
+
+ printf (" at %s MHz:", strmhz (buf, clock));
+
+ printf (" %u kB I-Cache", checkicache () >> 10);
+ printf (" %u kB D-Cache", checkdcache () >> 10);
+
+ /* lets check and see if we're running on a 860T (or P?) */
+
+ immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+ if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+ puts (" FEC present");
+ }
+
+ if (!m) {
+ puts (cpu_warning);
+ }
+
+ putc ('\n');
+
+ return 0;
+}
+
+#elif defined(CONFIG_MPC850)
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+ volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+ uint k, m;
+ char buf[32];
+
+ /* the highest 16 bits should be 0x0050 for a 8xx */
+
+ if ((pvr >> 16) != 0x0050)
+ return -1;
+
+ k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
+ m = 0;
+
+ switch (k) {
+ case 0x20020001:
+ printf ("XPC850xxZT");
+ break;
+ case 0x21000065:
+ printf ("XPC850xxZTA");
+ break;
+ case 0x21010067:
+ printf ("XPC850xxZTB");
+ m = 1;
+ break;
+ case 0x21020068:
+ printf ("XPC850xxZTC");
+ m = 1;
+ break;
+ default:
+ printf ("unknown MPC850 (0x%08x)", k);
+ }
+ printf (" at %s MHz:", strmhz (buf, clock));
+
+ printf (" %u kB I-Cache", checkicache () >> 10);
+ printf (" %u kB D-Cache", checkdcache () >> 10);
+
+ /* lets check and see if we're running on a 850T (or P?) */
+
+ immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+ if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+ printf (" FEC present");
+ }
+
+ if (!m) {
+ puts (cpu_warning);
+ }
+
+ putc ('\n');
+
+ return 0;
+}
+#else
+#error CPU undefined
+#endif
+/* ------------------------------------------------------------------------- */
+
+int checkcpu (void)
+{
+ ulong clock = gd->cpu_clk;
+ uint immr = get_immr (0); /* Return full IMMR contents */
+ uint pvr = get_pvr ();
+
+ puts ("CPU: ");
+
+ /* 850 has PARTNUM 20 */
+ /* 801 has PARTNUM 10 */
+ return check_CPU (clock, pvr, immr);
+}
+
+/* ------------------------------------------------------------------------- */
+/* L1 i-cache */
+/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB) */
+/* the 860 P (plus) has 256 sets of 16 bytes in 4 ways (= 16 kB) */
+
+int checkicache (void)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ u32 cacheon = rd_ic_cst () & IDC_ENABLED;
+
+#ifdef CONFIG_IP86x
+ u32 k = memctl->memc_br1 & ~0x00007fff; /* probe in flash memoryarea */
+#else
+ u32 k = memctl->memc_br0 & ~0x00007fff; /* probe in flash memoryarea */
+#endif
+ u32 m;
+ u32 lines = -1;
+
+ wr_ic_cst (IDC_UNALL);
+ wr_ic_cst (IDC_INVALL);
+ wr_ic_cst (IDC_DISABLE);
+ __asm__ volatile ("isync");
+
+ while (!((m = rd_ic_cst ()) & IDC_CERR2)) {
+ wr_ic_adr (k);
+ wr_ic_cst (IDC_LDLCK);
+ __asm__ volatile ("isync");
+
+ lines++;
+ k += 0x10; /* the number of bytes in a cacheline */
+ }
+
+ wr_ic_cst (IDC_UNALL);
+ wr_ic_cst (IDC_INVALL);
+
+ if (cacheon)
+ wr_ic_cst (IDC_ENABLE);
+ else
+ wr_ic_cst (IDC_DISABLE);
+
+ __asm__ volatile ("isync");
+
+ return lines << 4;
+};
+
+/* ------------------------------------------------------------------------- */
+/* L1 d-cache */
+/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB) */
+/* the 860 P (plus) has 256 sets of 16 bytes in 2 ways (= 8 kB) */
+/* call with cache disabled */
+
+int checkdcache (void)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ u32 cacheon = rd_dc_cst () & IDC_ENABLED;
+
+#ifdef CONFIG_IP86x
+ u32 k = memctl->memc_br1 & ~0x00007fff; /* probe in flash memoryarea */
+#else
+ u32 k = memctl->memc_br0 & ~0x00007fff; /* probe in flash memoryarea */
+#endif
+ u32 m;
+ u32 lines = -1;
+
+ wr_dc_cst (IDC_UNALL);
+ wr_dc_cst (IDC_INVALL);
+ wr_dc_cst (IDC_DISABLE);
+
+ while (!((m = rd_dc_cst ()) & IDC_CERR2)) {
+ wr_dc_adr (k);
+ wr_dc_cst (IDC_LDLCK);
+ lines++;
+ k += 0x10; /* the number of bytes in a cacheline */
+ }
+
+ wr_dc_cst (IDC_UNALL);
+ wr_dc_cst (IDC_INVALL);
+
+ if (cacheon)
+ wr_dc_cst (IDC_ENABLE);
+ else
+ wr_dc_cst (IDC_DISABLE);
+
+ return lines << 4;
+};
+
+/* ------------------------------------------------------------------------- */
+
+void upmconfig (uint upm, uint * table, uint size)
+{
+ uint i;
+ uint addr = 0;
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+
+ for (i = 0; i < size; i++) {
+ memctl->memc_mdr = table[i]; /* (16-15) */
+ memctl->memc_mcr = addr | upm; /* (16-16) */
+ addr++;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+#ifndef CONFIG_LWMON
+
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ ulong msr, addr;
+
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ immap->im_clkrst.car_plprcr |= PLPRCR_CSR; /* Checkstop Reset enable */
+
+ /* Interrupts and MMU off */
+ __asm__ volatile ("mtspr 81, 0");
+ __asm__ volatile ("mfmsr %0":"=r" (msr));
+
+ msr &= ~0x1030;
+ __asm__ volatile ("mtmsr %0"::"r" (msr));
+
+ /*
+ * Trying to execute the next instruction at a non-existing address
+ * should cause a machine check, resulting in reset
+ */
+#ifdef 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.
+ * "(ulong)-1" used to be a good choice for many systems...
+ */
+ addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+ ((void (*)(void)) addr) ();
+ return 1;
+}
+
+#else /* CONFIG_LWMON */
+
+/*
+ * On the LWMON board, the MCLR reset input of the PIC's on the board
+ * uses a 47K/1n RC combination which has a 47us time constant. The
+ * low signal on the HRESET pin of the CPU is only 512 clocks = 8 us
+ * and thus too short to reset the external hardware. So we use the
+ * watchdog to reset the board.
+ */
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ /* prevent triggering the watchdog */
+ disable_interrupts ();
+
+ /* make sure the watchdog is running */
+ reset_8xx_watchdog ((immap_t *) CONFIG_SYS_IMMR);
+
+ /* wait for watchdog reset */
+ while (1) {};
+
+ /* NOTREACHED */
+ return 1;
+}
+
+#endif /* CONFIG_LWMON */
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ * See sections 14.2 and 14.6 of the User's Manual
+ */
+unsigned long get_tbclk (void)
+{
+ uint immr = get_immr (0); /* Return full IMMR contents */
+ volatile immap_t *immap = (volatile immap_t *)(immr & 0xFFFF0000);
+ ulong oscclk, factor, pll;
+
+ if (immap->im_clkrst.car_sccr & SCCR_TBS) {
+ return (gd->cpu_clk / 16);
+ }
+
+ pll = immap->im_clkrst.car_plprcr;
+
+#define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT)
+
+ /*
+ * For newer PQ1 chips (MPC866/87x/88x families), PLL multiplication
+ * factor is calculated as follows:
+ *
+ * MFN
+ * MFI + -------
+ * MFD + 1
+ * factor = -----------------
+ * (PDF + 1) * 2^S
+ *
+ * For older chips, it's just MF field of PLPRCR plus one.
+ */
+ if ((immr & 0x0FFF) >= MPC8xx_NEW_CLK) { /* MPC866/87x/88x series */
+ factor = (PLPRCR_val(MFI) + PLPRCR_val(MFN)/(PLPRCR_val(MFD)+1))/
+ (PLPRCR_val(PDF)+1) / (1<<PLPRCR_val(S));
+ } else {
+ factor = PLPRCR_val(MF)+1;
+ }
+
+ oscclk = gd->cpu_clk / factor;
+
+ if ((immap->im_clkrst.car_sccr & SCCR_RTSEL) == 0 || factor > 2) {
+ return (oscclk / 4);
+ }
+ return (oscclk / 16);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+ int re_enable = disable_interrupts ();
+
+ reset_8xx_watchdog ((immap_t *) CONFIG_SYS_IMMR);
+ if (re_enable)
+ enable_interrupts ();
+}
+#endif /* CONFIG_WATCHDOG */
+
+#if defined(CONFIG_WATCHDOG) || defined(CONFIG_LWMON)
+
+void reset_8xx_watchdog (volatile immap_t * immr)
+{
+# if defined(CONFIG_LWMON)
+ /*
+ * The LWMON board uses a MAX6301 Watchdog
+ * with the trigger pin connected to port PA.7
+ *
+ * (The old board version used a MAX706TESA Watchdog, which
+ * had to be handled exactly the same.)
+ */
+# define WATCHDOG_BIT 0x0100
+ immr->im_ioport.iop_papar &= ~(WATCHDOG_BIT); /* GPIO */
+ immr->im_ioport.iop_padir |= WATCHDOG_BIT; /* Output */
+ immr->im_ioport.iop_paodr &= ~(WATCHDOG_BIT); /* active output */
+
+ immr->im_ioport.iop_padat ^= WATCHDOG_BIT; /* Toggle WDI */
+# elif defined(CONFIG_KUP4K) || defined(CONFIG_KUP4X)
+ /*
+ * The KUP4 boards uses a TPS3705 Watchdog
+ * with the trigger pin connected to port PA.5
+ */
+# define WATCHDOG_BIT 0x0400
+ immr->im_ioport.iop_papar &= ~(WATCHDOG_BIT); /* GPIO */
+ immr->im_ioport.iop_padir |= WATCHDOG_BIT; /* Output */
+ immr->im_ioport.iop_paodr &= ~(WATCHDOG_BIT); /* active output */
+
+ immr->im_ioport.iop_padat ^= WATCHDOG_BIT; /* Toggle WDI */
+# else
+ /*
+ * All other boards use the MPC8xx Internal Watchdog
+ */
+ immr->im_siu_conf.sc_swsr = 0x556c; /* write magic1 */
+ immr->im_siu_conf.sc_swsr = 0xaa39; /* write magic2 */
+# endif /* CONFIG_LWMON */
+}
+#endif /* CONFIG_WATCHDOG */
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(SCC_ENET) && defined(CONFIG_CMD_NET)
+ scc_initialize(bis);
+#endif
+#if defined(FEC_ENET)
+ fec_initialize(bis);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8xx/cpu_init.c b/arch/powerpc/cpu/mpc8xx/cpu_init.c
new file mode 100644
index 0000000..eb0091b
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/cpu_init.c
@@ -0,0 +1,285 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+
+#include <mpc8xx.h>
+#include <commproc.h>
+
+#if defined(CONFIG_SYS_RTCSC) || defined(CONFIG_SYS_RMDS)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCH) || \
+ defined(CONFIG_SYS_SMC_UCODE_PATCH)
+void cpm_load_patch (volatile immap_t * immr);
+#endif
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ * initialize the UPM's
+ */
+void cpu_init_f (volatile immap_t * immr)
+{
+#ifndef CONFIG_MBX
+ volatile memctl8xx_t *memctl = &immr->im_memctl;
+# ifdef CONFIG_SYS_PLPRCR
+ ulong mfmask;
+# endif
+#endif
+ ulong reg;
+
+ /* SYPCR - contains watchdog control (11-9) */
+
+ immr->im_siu_conf.sc_sypcr = CONFIG_SYS_SYPCR;
+
+#if defined(CONFIG_WATCHDOG)
+ reset_8xx_watchdog (immr);
+#endif /* CONFIG_WATCHDOG */
+
+ /* SIUMCR - contains debug pin configuration (11-6) */
+#ifndef CONFIG_SVM_SC8xx
+ immr->im_siu_conf.sc_siumcr |= CONFIG_SYS_SIUMCR;
+#else
+ immr->im_siu_conf.sc_siumcr = CONFIG_SYS_SIUMCR;
+#endif
+ /* initialize timebase status and control register (11-26) */
+ /* unlock TBSCRK */
+
+ immr->im_sitk.sitk_tbscrk = KAPWR_KEY;
+ immr->im_sit.sit_tbscr = CONFIG_SYS_TBSCR;
+
+ /* initialize the PIT (11-31) */
+
+ immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+ immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
+
+ /* System integration timers. Don't change EBDF! (15-27) */
+
+ immr->im_clkrstk.cark_sccrk = KAPWR_KEY;
+ reg = immr->im_clkrst.car_sccr;
+ reg &= SCCR_MASK;
+ reg |= CONFIG_SYS_SCCR;
+ immr->im_clkrst.car_sccr = reg;
+
+ /* PLL (CPU clock) settings (15-30) */
+
+ immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+
+#ifndef CONFIG_MBX /* MBX board does things different */
+
+ /* If CONFIG_SYS_PLPRCR (set in the various *_config.h files) tries to
+ * set the MF field, then just copy CONFIG_SYS_PLPRCR over car_plprcr,
+ * otherwise OR in CONFIG_SYS_PLPRCR so we do not change the current MF
+ * field value.
+ *
+ * For newer (starting MPC866) chips PLPRCR layout is different.
+ */
+#ifdef CONFIG_SYS_PLPRCR
+ if (get_immr(0xFFFF) >= MPC8xx_NEW_CLK)
+ mfmask = PLPRCR_MFACT_MSK;
+ else
+ mfmask = PLPRCR_MF_MSK;
+
+ if ((CONFIG_SYS_PLPRCR & mfmask) != 0)
+ reg = CONFIG_SYS_PLPRCR; /* reset control bits */
+ else {
+ reg = immr->im_clkrst.car_plprcr;
+ reg &= mfmask; /* isolate MF-related fields */
+ reg |= CONFIG_SYS_PLPRCR; /* reset control bits */
+ }
+ immr->im_clkrst.car_plprcr = reg;
+#endif
+
+ /*
+ * Memory Controller:
+ */
+
+ /* perform BR0 reset that MPC850 Rev. A can't guarantee */
+ reg = memctl->memc_br0;
+ reg &= BR_PS_MSK; /* Clear everything except Port Size bits */
+ reg |= BR_V; /* then add just the "Bank Valid" bit */
+ memctl->memc_br0 = reg;
+
+ /* Map banks 0 (and maybe 1) to the FLASH banks 0 (and 1) at
+ * preliminary addresses - these have to be modified later
+ * when FLASH size has been determined
+ *
+ * Depending on the size of the memory region defined by
+ * CONFIG_SYS_OR0_REMAP some boards (wide address mask) allow to map the
+ * CONFIG_SYS_MONITOR_BASE, while others (narrower address mask) can't
+ * map CONFIG_SYS_MONITOR_BASE.
+ *
+ * For example, for CONFIG_IVMS8, the CONFIG_SYS_MONITOR_BASE is
+ * 0xff000000, but CONFIG_SYS_OR0_REMAP's address mask is 0xfff80000.
+ *
+ * If BR0 wasn't loaded with address base 0xff000000, then BR0's
+ * base address remains as 0x00000000. However, the address mask
+ * have been narrowed to 512Kb, so CONFIG_SYS_MONITOR_BASE wasn't mapped
+ * into the Bank0.
+ *
+ * This is why CONFIG_IVMS8 and similar boards must load BR0 with
+ * CONFIG_SYS_BR0_PRELIM in advance.
+ *
+ * [Thanks to Michael Liao for this explanation.
+ * I owe him a free beer. - wd]
+ */
+
+#if defined(CONFIG_GTH) || \
+ defined(CONFIG_HERMES) || \
+ defined(CONFIG_ICU862) || \
+ defined(CONFIG_IP860) || \
+ defined(CONFIG_IVML24) || \
+ defined(CONFIG_IVMS8) || \
+ defined(CONFIG_LWMON) || \
+ defined(CONFIG_MHPC) || \
+ defined(CONFIG_PCU_E) || \
+ defined(CONFIG_R360MPI) || \
+ defined(CONFIG_RMU) || \
+ defined(CONFIG_RPXCLASSIC) || \
+ defined(CONFIG_RPXLITE) || \
+ defined(CONFIG_SPC1920) || \
+ defined(CONFIG_SPD823TS)
+
+ memctl->memc_br0 = CONFIG_SYS_BR0_PRELIM;
+#endif
+
+#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
+#if defined(CONFIG_SYS_OR5_REMAP)
+ memctl->memc_or5 = CONFIG_SYS_OR5_REMAP;
+#endif
+
+ /* now restrict to preliminary range */
+ memctl->memc_br0 = CONFIG_SYS_BR0_PRELIM;
+ memctl->memc_or0 = CONFIG_SYS_OR0_PRELIM;
+
+#if (defined(CONFIG_SYS_OR1_PRELIM) && defined(CONFIG_SYS_BR1_PRELIM))
+ memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM;
+ memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM;
+#endif
+
+#if defined(CONFIG_IP860) /* disable CS0 now that Flash is mapped on CS1 */
+ memctl->memc_br0 = 0;
+#endif
+
+#if defined(CONFIG_SYS_OR2_PRELIM) && defined(CONFIG_SYS_BR2_PRELIM)
+ memctl->memc_or2 = CONFIG_SYS_OR2_PRELIM;
+ memctl->memc_br2 = CONFIG_SYS_BR2_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR3_PRELIM) && defined(CONFIG_SYS_BR3_PRELIM)
+ memctl->memc_or3 = CONFIG_SYS_OR3_PRELIM;
+ memctl->memc_br3 = CONFIG_SYS_BR3_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR4_PRELIM) && defined(CONFIG_SYS_BR4_PRELIM)
+ memctl->memc_or4 = CONFIG_SYS_OR4_PRELIM;
+ memctl->memc_br4 = CONFIG_SYS_BR4_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR5_PRELIM) && defined(CONFIG_SYS_BR5_PRELIM)
+ memctl->memc_or5 = CONFIG_SYS_OR5_PRELIM;
+ memctl->memc_br5 = CONFIG_SYS_BR5_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR6_PRELIM) && defined(CONFIG_SYS_BR6_PRELIM)
+ memctl->memc_or6 = CONFIG_SYS_OR6_PRELIM;
+ memctl->memc_br6 = CONFIG_SYS_BR6_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR7_PRELIM) && defined(CONFIG_SYS_BR7_PRELIM)
+ memctl->memc_or7 = CONFIG_SYS_OR7_PRELIM;
+ memctl->memc_br7 = CONFIG_SYS_BR7_PRELIM;
+#endif
+
+#endif /* ! CONFIG_MBX */
+
+ /*
+ * Reset CPM
+ */
+ immr->im_cpm.cp_cpcr = CPM_CR_RST | CPM_CR_FLG;
+ do { /* Spin until command processed */
+ __asm__ ("eieio");
+ } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+#ifdef CONFIG_MBX
+ /*
+ * on the MBX, things are a little bit different:
+ * - we need to read the VPD to get board information
+ * - the plprcr is set up dynamically
+ * - the memory controller is set up dynamically
+ */
+ mbx_init ();
+#endif /* CONFIG_MBX */
+
+#ifdef CONFIG_RPXCLASSIC
+ rpxclassic_init ();
+#endif
+
+#if defined(CONFIG_RPXLITE) && defined(CONFIG_ENV_IS_IN_NVRAM)
+ rpxlite_init ();
+#endif
+
+#ifdef CONFIG_SYS_RCCR /* must be done before cpm_load_patch() */
+ /* write config value */
+ immr->im_cpm.cp_rccr = CONFIG_SYS_RCCR;
+#endif
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCH) || \
+ defined(CONFIG_SYS_SMC_UCODE_PATCH)
+ cpm_load_patch (immr); /* load mpc8xx microcode patch */
+#endif
+}
+
+/*
+ * initialize higher level parts of CPU like timers
+ */
+int cpu_init_r (void)
+{
+#if defined(CONFIG_SYS_RTCSC) || defined(CONFIG_SYS_RMDS)
+ bd_t *bd = gd->bd;
+ volatile immap_t *immr = (volatile immap_t *) (bd->bi_immr_base);
+#endif
+
+#ifdef CONFIG_SYS_RTCSC
+ /* Unlock RTSC register */
+ immr->im_sitk.sitk_rtcsck = KAPWR_KEY;
+ /* write config value */
+ immr->im_sit.sit_rtcsc = CONFIG_SYS_RTCSC;
+#endif
+
+#ifdef CONFIG_SYS_RMDS
+ /* write config value */
+ immr->im_cpm.cp_rmds = CONFIG_SYS_RMDS;
+#endif
+ return (0);
+}
diff --git a/arch/powerpc/cpu/mpc8xx/fdt.c b/arch/powerpc/cpu/mpc8xx/fdt.c
new file mode 100644
index 0000000..7130983
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/fdt.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008 (C) Bryan O'Donoghue
+ *
+ * Code copied & edited from Freescale mpc85xx stuff.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "timebase-frequency", get_tbclk(), 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,
+ "clock-frequency", bd->bi_intfreq, 1);
+ do_fixup_by_compat_u32(blob, "fsl,cpm-brg", "clock-frequency",
+ gd->brg_clk, 1);
+
+ /* Fixup ethernet MAC addresses */
+ fdt_fixup_ethernet(blob);
+
+ fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+}
diff --git a/arch/powerpc/cpu/mpc8xx/fec.c b/arch/powerpc/cpu/mpc8xx/fec.c
new file mode 100644
index 0000000..89c1ff9
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/fec.c
@@ -0,0 +1,1026 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <commproc.h>
+#include <net.h>
+#include <command.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#undef ET_DEBUG
+
+#if defined(CONFIG_CMD_NET) && \
+ (defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FEC1) || defined(CONFIG_ETHER_ON_FEC2))
+
+/* compatibility test, if only FEC_ENET defined assume ETHER on FEC1 */
+#if defined(FEC_ENET) && !defined(CONFIG_ETHER_ON_FEC1) && !defined(CONFIG_ETHER_ON_FEC2)
+#define CONFIG_ETHER_ON_FEC1 1
+#endif
+
+/* define WANT_MII when MII support is required */
+#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_FEC1_PHY) || defined(CONFIG_FEC2_PHY)
+#define WANT_MII
+#else
+#undef WANT_MII
+#endif
+
+#if defined(WANT_MII)
+#include <miiphy.h>
+
+#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#endif
+
+#if defined(CONFIG_RMII) && !defined(WANT_MII)
+#error RMII support is unusable without a working PHY.
+#endif
+
+#ifdef CONFIG_SYS_DISCOVER_PHY
+static int mii_discover_phy(struct eth_device *dev);
+#endif
+
+int fec8xx_miiphy_read(char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value);
+int fec8xx_miiphy_write(char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value);
+
+static struct ether_fcc_info_s
+{
+ int ether_index;
+ int fecp_offset;
+ int phy_addr;
+ int actual_phy_addr;
+ int initialized;
+}
+ ether_fcc_info[] = {
+#if defined(CONFIG_ETHER_ON_FEC1)
+ {
+ 0,
+ offsetof(immap_t, im_cpm.cp_fec1),
+#if defined(CONFIG_FEC1_PHY)
+ CONFIG_FEC1_PHY,
+#else
+ -1, /* discover */
+#endif
+ -1,
+ 0,
+
+ },
+#endif
+#if defined(CONFIG_ETHER_ON_FEC2)
+ {
+ 1,
+ offsetof(immap_t, im_cpm.cp_fec2),
+#if defined(CONFIG_FEC2_PHY)
+ CONFIG_FEC2_PHY,
+#else
+ -1,
+#endif
+ -1,
+ 0,
+ },
+#endif
+};
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH 1520
+
+#define TX_BUF_CNT 2
+
+#define TOUT_LOOP 100
+
+#define PKT_MAXBUF_SIZE 1518
+#define PKT_MINBUF_SIZE 64
+#define PKT_MAXBLR_SIZE 1520
+
+#ifdef __GNUC__
+static char txbuf[DBUF_LENGTH] __attribute__ ((aligned(8)));
+#else
+#error txbuf must be aligned.
+#endif
+
+static uint rxIdx; /* index of the current RX buffer */
+static uint txIdx; /* index of the current TX buffer */
+
+/*
+ * FEC 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 = NULL;
+
+static int fec_send(struct eth_device* dev, volatile void *packet, int length);
+static int fec_recv(struct eth_device* dev);
+static int fec_init(struct eth_device* dev, bd_t * bd);
+static void fec_halt(struct eth_device* dev);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+static void __mii_init(void);
+#endif
+
+int fec_initialize(bd_t *bis)
+{
+ struct eth_device* dev;
+ struct ether_fcc_info_s *efis;
+ int i;
+
+ for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++) {
+
+ dev = malloc(sizeof(*dev));
+ if (dev == NULL)
+ hang();
+
+ memset(dev, 0, sizeof(*dev));
+
+ /* for FEC1 make sure that the name of the interface is the same
+ as the old one for compatibility reasons */
+ if (i == 0) {
+ sprintf (dev->name, "FEC ETHERNET");
+ } else {
+ sprintf (dev->name, "FEC%d ETHERNET",
+ ether_fcc_info[i].ether_index + 1);
+ }
+
+ efis = &ether_fcc_info[i];
+
+ /*
+ * reset actual phy addr
+ */
+ efis->actual_phy_addr = -1;
+
+ dev->priv = efis;
+ dev->init = fec_init;
+ dev->halt = fec_halt;
+ dev->send = fec_send;
+ dev->recv = fec_recv;
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name,
+ fec8xx_miiphy_read, fec8xx_miiphy_write);
+#endif
+ }
+ return 1;
+}
+
+static int fec_send(struct eth_device* dev, volatile void *packet, int length)
+{
+ int j, rc;
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+ /* section 16.9.23.3
+ * Wait for ready
+ */
+ j = 0;
+ while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+ udelay(1);
+ j++;
+ }
+ if (j>=TOUT_LOOP) {
+ printf("TX not ready\n");
+ }
+
+ 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;
+ __asm__ ("eieio");
+
+ /* Activate transmit Buffer Descriptor polling */
+ fecp->fec_x_des_active = 0x01000000; /* Descriptor polling active */
+
+ j = 0;
+ while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+#if defined(CONFIG_ICU862)
+ udelay(10);
+#else
+ udelay(1);
+#endif
+ j++;
+ }
+ if (j>=TOUT_LOOP) {
+ printf("TX timeout\n");
+ }
+#ifdef ET_DEBUG
+ printf("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n",
+ __FILE__,__LINE__,__FUNCTION__,j,rtx->txbd[txIdx].cbd_sc,
+ (rtx->txbd[txIdx].cbd_sc & 0x003C)>>2);
+#endif
+ /* return only status bits */;
+ rc = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS);
+
+ txIdx = (txIdx + 1) % TX_BUF_CNT;
+
+ return rc;
+}
+
+static int fec_recv (struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp =
+ (volatile fec_t *) (CONFIG_SYS_IMMR + efis->fecp_offset);
+ int length;
+
+ for (;;) {
+ /* section 16.9.23.2 */
+ 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) {
+#ifdef ET_DEBUG
+ printf ("%s[%d] err: %x\n",
+ __FUNCTION__, __LINE__,
+ rtx->rxbd[rxIdx].cbd_sc);
+#endif
+ } else {
+ volatile uchar *rx = NetRxPackets[rxIdx];
+
+ length -= 4;
+
+#if defined(CONFIG_CMD_CDP)
+ if ((rx[0] & 1) != 0
+ && memcmp ((uchar *) rx, NetBcastAddr, 6) != 0
+ && memcmp ((uchar *) rx, NetCDPAddr, 6) != 0)
+ rx = NULL;
+#endif
+ /*
+ * Pass the packet up to the protocol layers.
+ */
+ if (rx != NULL)
+ NetReceive (rx, length);
+ }
+
+ /* Give the buffer back to the FEC. */
+ 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++;
+ }
+
+ __asm__ ("eieio");
+
+ /* Try to fill Buffer Descriptors */
+ fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
+ }
+
+ return length;
+}
+
+/**************************************************************
+ *
+ * FEC Ethernet Initialization Routine
+ *
+ *************************************************************/
+
+#define FEC_ECNTRL_PINMUX 0x00000004
+#define FEC_ECNTRL_ETHER_EN 0x00000002
+#define FEC_ECNTRL_RESET 0x00000001
+
+#define FEC_RCNTRL_BC_REJ 0x00000010
+#define FEC_RCNTRL_PROM 0x00000008
+#define FEC_RCNTRL_MII_MODE 0x00000004
+#define FEC_RCNTRL_DRT 0x00000002
+#define FEC_RCNTRL_LOOP 0x00000001
+
+#define FEC_TCNTRL_FDEN 0x00000004
+#define FEC_TCNTRL_HBC 0x00000002
+#define FEC_TCNTRL_GTS 0x00000001
+
+#define FEC_RESET_DELAY 50
+
+#if defined(CONFIG_RMII)
+
+static inline void fec_10Mbps(struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ int fecidx = efis->ether_index;
+ uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
+
+ if ((unsigned int)fecidx >= 2)
+ hang();
+
+ ((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_cptr |= mask;
+}
+
+static inline void fec_100Mbps(struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ int fecidx = efis->ether_index;
+ uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
+
+ if ((unsigned int)fecidx >= 2)
+ hang();
+
+ ((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_cptr &= ~mask;
+}
+
+#endif
+
+static inline void fec_full_duplex(struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+ fecp->fec_r_cntrl &= ~FEC_RCNTRL_DRT;
+ fecp->fec_x_cntrl |= FEC_TCNTRL_FDEN; /* FD enable */
+}
+
+static inline void fec_half_duplex(struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+ fecp->fec_r_cntrl |= FEC_RCNTRL_DRT;
+ fecp->fec_x_cntrl &= ~FEC_TCNTRL_FDEN; /* FD disable */
+}
+
+static void fec_pin_init(int fecidx)
+{
+ bd_t *bd = gd->bd;
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile fec_t *fecp;
+
+ /*
+ * only two FECs please
+ */
+ if ((unsigned int)fecidx >= 2)
+ hang();
+
+ if (fecidx == 0)
+ fecp = &immr->im_cpm.cp_fec1;
+ else
+ fecp = &immr->im_cpm.cp_fec2;
+
+ /*
+ * Set MII speed to 2.5 MHz or slightly below.
+ * * According to the MPC860T (Rev. D) Fast ethernet controller user
+ * * manual (6.2.14),
+ * * the MII management interface clock must be less than or equal
+ * * to 2.5 MHz.
+ * * This MDC frequency is equal to system clock / (2 * MII_SPEED).
+ * * Then MII_SPEED = system_clock / 2 * 2,5 MHz.
+ *
+ * All MII configuration is done via FEC1 registers:
+ */
+ immr->im_cpm.cp_fec1.fec_mii_speed = ((bd->bi_intfreq + 4999999) / 5000000) << 1;
+
+#if defined(CONFIG_NETTA) || defined(CONFIG_NETPHONE) || defined(CONFIG_NETTA2)
+ /* our PHYs are the limit at 2.5 MHz */
+ fecp->fec_mii_speed <<= 1;
+#endif
+
+#if defined(CONFIG_MPC885_FAMILY) && defined(WANT_MII)
+ /* use MDC for MII */
+ immr->im_ioport.iop_pdpar |= 0x0080;
+ immr->im_ioport.iop_pddir &= ~0x0080;
+#endif
+
+ if (fecidx == 0) {
+#if defined(CONFIG_ETHER_ON_FEC1)
+
+#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */
+
+#if !defined(CONFIG_RMII)
+
+ immr->im_ioport.iop_papar |= 0xf830;
+ immr->im_ioport.iop_padir |= 0x0830;
+ immr->im_ioport.iop_padir &= ~0xf000;
+
+ immr->im_cpm.cp_pbpar |= 0x00001001;
+ immr->im_cpm.cp_pbdir &= ~0x00001001;
+
+ immr->im_ioport.iop_pcpar |= 0x000c;
+ immr->im_ioport.iop_pcdir &= ~0x000c;
+
+ immr->im_cpm.cp_pepar |= 0x00000003;
+ immr->im_cpm.cp_pedir |= 0x00000003;
+ immr->im_cpm.cp_peso &= ~0x00000003;
+
+ immr->im_cpm.cp_cptr &= ~0x00000100;
+
+#else
+
+#if !defined(CONFIG_FEC1_PHY_NORXERR)
+ immr->im_ioport.iop_papar |= 0x1000;
+ immr->im_ioport.iop_padir &= ~0x1000;
+#endif
+ immr->im_ioport.iop_papar |= 0xe810;
+ immr->im_ioport.iop_padir |= 0x0810;
+ immr->im_ioport.iop_padir &= ~0xe000;
+
+ immr->im_cpm.cp_pbpar |= 0x00000001;
+ immr->im_cpm.cp_pbdir &= ~0x00000001;
+
+ immr->im_cpm.cp_cptr |= 0x00000100;
+ immr->im_cpm.cp_cptr &= ~0x00000050;
+
+#endif /* !CONFIG_RMII */
+
+#elif !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210)
+ /*
+ * Configure all of port D for MII.
+ */
+ immr->im_ioport.iop_pdpar = 0x1fff;
+
+ /*
+ * Bits moved from Rev. D onward
+ */
+ if ((get_immr(0) & 0xffff) < 0x0501)
+ immr->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */
+ else
+ immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */
+#else
+ /*
+ * Configure port A for MII.
+ */
+
+#if defined(CONFIG_ICU862) && defined(CONFIG_SYS_DISCOVER_PHY)
+
+ /*
+ * On the ICU862 board the MII-MDC pin is routed to PD8 pin
+ * * of CPU, so for this board we need to configure Utopia and
+ * * enable PD8 to MII-MDC function
+ */
+ immr->im_ioport.iop_pdpar |= 0x4080;
+#endif
+
+ /*
+ * Has Utopia been configured?
+ */
+ if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) {
+ /*
+ * YES - Use MUXED mode for UTOPIA bus.
+ * This frees Port A for use by MII (see 862UM table 41-6).
+ */
+ immr->im_ioport.utmode &= ~0x80;
+ } else {
+ /*
+ * NO - set SPLIT mode for UTOPIA bus.
+ *
+ * This doesn't really effect UTOPIA (which isn't
+ * enabled anyway) but just tells the 862
+ * to use port A for MII (see 862UM table 41-6).
+ */
+ immr->im_ioport.utmode |= 0x80;
+ }
+#endif /* !defined(CONFIG_ICU862) */
+
+#endif /* CONFIG_ETHER_ON_FEC1 */
+ } else if (fecidx == 1) {
+
+#if defined(CONFIG_ETHER_ON_FEC2)
+
+#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */
+
+#if !defined(CONFIG_RMII)
+ immr->im_cpm.cp_pepar |= 0x0003fffc;
+ immr->im_cpm.cp_pedir |= 0x0003fffc;
+ immr->im_cpm.cp_peso &= ~0x000087fc;
+ immr->im_cpm.cp_peso |= 0x00037800;
+
+ immr->im_cpm.cp_cptr &= ~0x00000080;
+#else
+
+#if !defined(CONFIG_FEC2_PHY_NORXERR)
+ immr->im_cpm.cp_pepar |= 0x00000010;
+ immr->im_cpm.cp_pedir |= 0x00000010;
+ immr->im_cpm.cp_peso &= ~0x00000010;
+#endif
+ immr->im_cpm.cp_pepar |= 0x00039620;
+ immr->im_cpm.cp_pedir |= 0x00039620;
+ immr->im_cpm.cp_peso |= 0x00031000;
+ immr->im_cpm.cp_peso &= ~0x00008620;
+
+ immr->im_cpm.cp_cptr |= 0x00000080;
+ immr->im_cpm.cp_cptr &= ~0x00000028;
+#endif /* CONFIG_RMII */
+
+#endif /* CONFIG_MPC885_FAMILY */
+
+#endif /* CONFIG_ETHER_ON_FEC2 */
+
+ }
+}
+
+static int fec_reset(volatile fec_t *fecp)
+{
+ int i;
+
+ /* Whack a reset.
+ * A delay is required between a reset of the FEC block and
+ * initialization of other FEC registers because the reset takes
+ * some time to complete. If you don't delay, subsequent writes
+ * to FEC registers might get killed by the reset routine which is
+ * still in progress.
+ */
+
+ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+ for (i = 0;
+ (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+ ++i) {
+ udelay (1);
+ }
+ if (i == FEC_RESET_DELAY)
+ return -1;
+
+ return 0;
+}
+
+static int fec_init (struct eth_device *dev, bd_t * bd)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile fec_t *fecp =
+ (volatile fec_t *) (CONFIG_SYS_IMMR + efis->fecp_offset);
+ int i;
+
+ if (efis->ether_index == 0) {
+#if defined(CONFIG_FADS) /* FADS family uses FPGA (BCSR) to control PHYs */
+#if defined(CONFIG_MPC885ADS)
+ *(vu_char *) BCSR5 &= ~(BCSR5_MII1_EN | BCSR5_MII1_RST);
+#else
+ /* configure FADS for fast (FEC) ethernet, half-duplex */
+ /* The LXT970 needs about 50ms to recover from reset, so
+ * wait for it by discovering the PHY before leaving eth_init().
+ */
+ {
+ volatile uint *bcsr4 = (volatile uint *) BCSR4;
+
+ *bcsr4 = (*bcsr4 & ~(BCSR4_FETH_EN | BCSR4_FETHCFG1))
+ | (BCSR4_FETHCFG0 | BCSR4_FETHFDE |
+ BCSR4_FETHRST);
+
+ /* reset the LXT970 PHY */
+ *bcsr4 &= ~BCSR4_FETHRST;
+ udelay (10);
+ *bcsr4 |= BCSR4_FETHRST;
+ udelay (10);
+ }
+#endif /* CONFIG_MPC885ADS */
+#endif /* CONFIG_FADS */
+ }
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ /* the MII interface is connected to FEC1
+ * so for the miiphy_xxx function to work we must
+ * call mii_init since fec_halt messes the thing up
+ */
+ if (efis->ether_index != 0)
+ __mii_init();
+#endif
+
+ if (fec_reset(fecp) < 0)
+ printf ("FEC_RESET_DELAY timeout\n");
+
+ /* We use strictly polling mode only
+ */
+ fecp->fec_imask = 0;
+
+ /* Clear any pending interrupt
+ */
+ fecp->fec_ievent = 0xffc0;
+
+ /* No need to set the IVEC register */
+
+ /* Set station address
+ */
+#define ea dev->enetaddr
+ fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
+ fecp->fec_addr_high = (ea[4] << 8) | (ea[5]);
+#undef ea
+
+#if defined(CONFIG_CMD_CDP)
+ /*
+ * Turn on multicast address hash table
+ */
+ fecp->fec_hash_table_high = 0xffffffff;
+ fecp->fec_hash_table_low = 0xffffffff;
+#else
+ /* Clear multicast address hash table
+ */
+ fecp->fec_hash_table_high = 0;
+ fecp->fec_hash_table_low = 0;
+#endif
+
+ /* Set maximum receive buffer size.
+ */
+ fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
+
+ /* Set maximum frame length
+ */
+ fecp->fec_r_hash = PKT_MAXBUF_SIZE;
+
+ /*
+ * Setup Buffers and Buffer Desriptors
+ */
+ rxIdx = 0;
+ txIdx = 0;
+
+ if (!rtx) {
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ rtx = (RTXBD *) (immr->im_cpm.cp_dpmem +
+ dpram_alloc_align (sizeof (RTXBD), 8));
+#else
+ rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_FEC_BASE);
+#endif
+ }
+ /*
+ * Setup Receiver Buffer Descriptors (13.14.24.18)
+ * Settings:
+ * Empty, Wrap
+ */
+ 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) NetRxPackets[i];
+ }
+ rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /*
+ * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
+ * Settings:
+ * Last, Tx CRC
+ */
+ for (i = 0; i < TX_BUF_CNT; i++) {
+ rtx->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC;
+ rtx->txbd[i].cbd_datlen = 0; /* Reset */
+ rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]);
+ }
+ rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /* Set receive and transmit descriptor base
+ */
+ fecp->fec_r_des_start = (unsigned int) (&rtx->rxbd[0]);
+ fecp->fec_x_des_start = (unsigned int) (&rtx->txbd[0]);
+
+ /* Enable MII mode
+ */
+#if 0 /* Full duplex mode */
+ fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE;
+ fecp->fec_x_cntrl = FEC_TCNTRL_FDEN;
+#else /* Half duplex mode */
+ fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT;
+ fecp->fec_x_cntrl = 0;
+#endif
+
+ /* Enable big endian and don't care about SDMA FC.
+ */
+ fecp->fec_fun_code = 0x78000000;
+
+ /*
+ * Setup the pin configuration of the FEC
+ */
+ fec_pin_init (efis->ether_index);
+
+ rxIdx = 0;
+ txIdx = 0;
+
+ /*
+ * Now enable the transmit and receive processing
+ */
+ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+
+ if (efis->phy_addr == -1) {
+#ifdef CONFIG_SYS_DISCOVER_PHY
+ /*
+ * wait for the PHY to wake up after reset
+ */
+ efis->actual_phy_addr = mii_discover_phy (dev);
+
+ if (efis->actual_phy_addr == -1) {
+ printf ("Unable to discover phy!\n");
+ return -1;
+ }
+#else
+ efis->actual_phy_addr = -1;
+#endif
+ } else {
+ efis->actual_phy_addr = efis->phy_addr;
+ }
+
+#if defined(CONFIG_MII) && defined(CONFIG_RMII)
+ /*
+ * adapt the RMII speed to the speed of the phy
+ */
+ if (miiphy_speed (dev->name, efis->actual_phy_addr) == _100BASET) {
+ fec_100Mbps (dev);
+ } else {
+ fec_10Mbps (dev);
+ }
+#endif
+
+#if defined(CONFIG_MII)
+ /*
+ * adapt to the half/full speed settings
+ */
+ if (miiphy_duplex (dev->name, efis->actual_phy_addr) == FULL) {
+ fec_full_duplex (dev);
+ } else {
+ fec_half_duplex (dev);
+ }
+#endif
+
+ /* And last, try to fill Rx Buffer Descriptors */
+ fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
+
+ efis->initialized = 1;
+
+ return 0;
+}
+
+
+static void fec_halt(struct eth_device* dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+ int i;
+
+ /* avoid halt if initialized; mii gets stuck otherwise */
+ if (!efis->initialized)
+ return;
+
+ /* Whack a reset.
+ * A delay is required between a reset of the FEC block and
+ * initialization of other FEC registers because the reset takes
+ * some time to complete. If you don't delay, subsequent writes
+ * to FEC registers might get killed by the reset routine which is
+ * still in progress.
+ */
+
+ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+ for (i = 0;
+ (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+ ++i) {
+ udelay (1);
+ }
+ if (i == FEC_RESET_DELAY) {
+ printf ("FEC_RESET_DELAY timeout\n");
+ return;
+ }
+
+ efis->initialized = 0;
+}
+
+#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+/* Make MII read/write commands for the FEC.
+*/
+
+#define mk_mii_read(ADDR, REG) (0x60020000 | ((ADDR << 23) | \
+ (REG & 0x1f) << 18))
+
+#define mk_mii_write(ADDR, REG, VAL) (0x50020000 | ((ADDR << 23) | \
+ (REG & 0x1f) << 18) | \
+ (VAL & 0xffff))
+
+/* Interrupt events/masks.
+*/
+#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
+#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */
+#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */
+#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */
+#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */
+#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */
+#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */
+#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
+#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
+#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
+
+/* PHY identification
+ */
+#define PHY_ID_LXT970 0x78100000 /* LXT970 */
+#define PHY_ID_LXT971 0x001378e0 /* LXT971 and 972 */
+#define PHY_ID_82555 0x02a80150 /* Intel 82555 */
+#define PHY_ID_QS6612 0x01814400 /* QS6612 */
+#define PHY_ID_AMD79C784 0x00225610 /* AMD 79C784 */
+#define PHY_ID_LSI80225 0x0016f870 /* LSI 80225 */
+#define PHY_ID_LSI80225B 0x0016f880 /* LSI 80225/B */
+#define PHY_ID_DM9161 0x0181B880 /* Davicom DM9161 */
+#define PHY_ID_KSM8995M 0x00221450 /* MICREL KS8995MA */
+
+/* send command to phy using mii, wait for result */
+static uint
+mii_send(uint mii_cmd)
+{
+ uint mii_reply;
+ volatile fec_t *ep;
+ int cnt;
+
+ ep = &(((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_fec);
+
+ ep->fec_mii_data = mii_cmd; /* command to phy */
+
+ /* wait for mii complete */
+ cnt = 0;
+ while (!(ep->fec_ievent & FEC_ENET_MII)) {
+ if (++cnt > 1000) {
+ printf("mii_send STUCK!\n");
+ break;
+ }
+ }
+ mii_reply = ep->fec_mii_data; /* result from phy */
+ ep->fec_ievent = FEC_ENET_MII; /* clear MII complete */
+#if 0
+ printf("%s[%d] %s: sent=0x%8.8x, reply=0x%8.8x\n",
+ __FILE__,__LINE__,__FUNCTION__,mii_cmd,mii_reply);
+#endif
+ return (mii_reply & 0xffff); /* data read from phy */
+}
+#endif
+
+#if defined(CONFIG_SYS_DISCOVER_PHY)
+static int mii_discover_phy(struct eth_device *dev)
+{
+#define MAX_PHY_PASSES 11
+ uint phyno;
+ int pass;
+ uint phytype;
+ int phyaddr;
+
+ phyaddr = -1; /* didn't find a PHY yet */
+ for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) {
+ if (pass > 1) {
+ /* PHY may need more time to recover from reset.
+ * The LXT970 needs 50ms typical, no maximum is
+ * specified, so wait 10ms before try again.
+ * With 11 passes this gives it 100ms to wake up.
+ */
+ udelay(10000); /* wait 10ms */
+ }
+ for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) {
+ phytype = mii_send(mk_mii_read(phyno, PHY_PHYIDR2));
+#ifdef ET_DEBUG
+ printf("PHY type 0x%x pass %d type ", phytype, pass);
+#endif
+ if (phytype != 0xffff) {
+ phyaddr = phyno;
+ phytype |= mii_send(mk_mii_read(phyno,
+ PHY_PHYIDR1)) << 16;
+
+#ifdef ET_DEBUG
+ printf("PHY @ 0x%x pass %d type ",phyno,pass);
+ switch (phytype & 0xfffffff0) {
+ case PHY_ID_LXT970:
+ printf("LXT970\n");
+ break;
+ case PHY_ID_LXT971:
+ printf("LXT971\n");
+ break;
+ case PHY_ID_82555:
+ printf("82555\n");
+ break;
+ case PHY_ID_QS6612:
+ printf("QS6612\n");
+ break;
+ case PHY_ID_AMD79C784:
+ printf("AMD79C784\n");
+ break;
+ case PHY_ID_LSI80225B:
+ printf("LSI L80225/B\n");
+ break;
+ case PHY_ID_DM9161:
+ printf("Davicom DM9161\n");
+ break;
+ case PHY_ID_KSM8995M:
+ printf("MICREL KS8995M\n");
+ break;
+ default:
+ printf("0x%08x\n", phytype);
+ break;
+ }
+#endif
+ }
+ }
+ }
+ if (phyaddr < 0) {
+ printf("No PHY device found.\n");
+ }
+ return phyaddr;
+}
+#endif /* CONFIG_SYS_DISCOVER_PHY */
+
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && !defined(CONFIG_BITBANGMII)
+
+/****************************************************************************
+ * mii_init -- Initialize the MII via FEC 1 for MII command without ethernet
+ * This function is a subset of eth_init
+ ****************************************************************************
+ */
+static void __mii_init(void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
+
+ if (fec_reset(fecp) < 0)
+ printf ("FEC_RESET_DELAY timeout\n");
+
+ /* We use strictly polling mode only
+ */
+ fecp->fec_imask = 0;
+
+ /* Clear any pending interrupt
+ */
+ fecp->fec_ievent = 0xffc0;
+
+ /* Now enable the transmit and receive processing
+ */
+ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+}
+
+void mii_init (void)
+{
+ int i;
+
+ __mii_init();
+
+ /* Setup the pin configuration of the FEC(s)
+ */
+ for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++)
+ fec_pin_init(ether_fcc_info[i].ether_index);
+}
+
+/*****************************************************************************
+ * Read and write a MII PHY register, routines used by MII Utilities
+ *
+ * FIXME: These routines are expected to return 0 on success, but mii_send
+ * does _not_ return an error code. Maybe 0xFFFF means error, i.e.
+ * no PHY connected...
+ * For now always return 0.
+ * FIXME: These routines only work after calling eth_init() at least once!
+ * Otherwise they hang in mii_send() !!! Sorry!
+ *****************************************************************************/
+
+int fec8xx_miiphy_read(char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ short rdreg; /* register working value */
+
+#ifdef MII_DEBUG
+ printf ("miiphy_read(0x%x) @ 0x%x = ", reg, addr);
+#endif
+ rdreg = mii_send(mk_mii_read(addr, reg));
+
+ *value = rdreg;
+#ifdef MII_DEBUG
+ printf ("0x%04x\n", *value);
+#endif
+ return 0;
+}
+
+int fec8xx_miiphy_write(char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ short rdreg; /* register working value */
+#ifdef MII_DEBUG
+ printf ("miiphy_write(0x%x) @ 0x%x = ", reg, addr);
+#endif
+ rdreg = mii_send(mk_mii_write(addr, reg, value));
+
+#ifdef MII_DEBUG
+ printf ("0x%04x\n", value);
+#endif
+ return 0;
+}
+#endif
+
+#endif
diff --git a/arch/powerpc/cpu/mpc8xx/fec.h b/arch/powerpc/cpu/mpc8xx/fec.h
new file mode 100644
index 0000000..a49417c
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/fec.h
@@ -0,0 +1,28 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _FEC_H_
+#define _FEC_H_
+
+
+#endif /* _FEC_H_ */
diff --git a/arch/powerpc/cpu/mpc8xx/i2c.c b/arch/powerpc/cpu/mpc8xx/i2c.c
new file mode 100644
index 0000000..338caba
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/i2c.c
@@ -0,0 +1,707 @@
+/*
+ * (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>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Back ported to the 8xx platform (from the 8260 platform) by
+ * Murray.Jensen@cmst.csiro.au, 27-Jan-01.
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_HARD_I2C
+
+#include <commproc.h>
+#include <i2c.h>
+#ifdef CONFIG_LWMON
+#include <watchdog.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* define to enable debug messages */
+#undef DEBUG_I2C
+
+/* tx/rx timeout (we need the i2c early, so we don't use get_timer()) */
+#define TOUT_LOOP 1000000
+
+#define NUM_RX_BDS 4
+#define NUM_TX_BDS 4
+#define MAX_TX_SPACE 256
+#define I2C_RXTX_LEN 128 /* maximum tx/rx buffer length */
+
+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
+
+typedef void (*i2c_ecb_t)(int, int); /* 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 */
+} 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 0x01 /* no more BDs or buffer space */
+#define I2CERR_MSG_TOO_LONG 0x02 /* tried to send/receive to much data */
+#define I2CERR_TIMEOUT 0x03 /* timeout in i2c_doio() */
+#define I2CERR_QUEUE_EMPTY 0x04 /* i2c_doio called without send/receive */
+
+/* error callback flags */
+#define I2CECB_RX_ERR 0x10 /* this is a receive error */
+#define I2CECB_RX_ERR_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 */
+
+#ifdef DEBUG_I2C
+#define PRINTD(x) printf x
+#else
+#define PRINTD(x)
+#endif
+
+/*
+ * 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;
+
+ PRINTD(("\t[I2C] trying hz=%d, speed=%d, filter=%d, modval=%d\n",
+ hz, speed, filter, modval));
+
+ div = moddiv * speed;
+ brgdiv = (hz + div - 1) / div;
+
+ PRINTD(("\t\tmoddiv=%d, brgdiv=%d\n", moddiv, brgdiv));
+
+ *brgval = ((brgdiv + 1) / 2) - 3 - (2*filter);
+
+ if ((*brgval < 0) || (*brgval > 255)) {
+ PRINTD(("\t\trejected brgval=%d\n", *brgval));
+ return -1;
+ }
+
+ brgdiv = 2 * (*brgval + 3 + (2 * filter));
+ div = moddiv * brgdiv ;
+ *totspeed = hz / div;
+
+ PRINTD(("\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 i2c8xx_t *i2c = (i2c8xx_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;
+ }
+ }
+ }
+
+ PRINTD (("[I2C] Best is:\n"));
+ PRINTD (("[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;
+
+ PRINTD (("[I2C] i2mod=%08x i2brg=%08x\n", i2c->i2c_i2mod,
+ i2c->i2c_i2brg));
+
+ return 1;
+}
+
+void
+i2c_init(int speed, int slaveaddr)
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ;
+ volatile cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm;
+ volatile i2c8xx_t *i2c = (i2c8xx_t *)&immap->im_i2c;
+ volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+ 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
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+ iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#else
+ /* Disable relocation */
+ iip->iic_rpbase = 0;
+#endif
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ dpaddr = iip->iic_rbase;
+ if (dpaddr == 0) {
+ /* need to allocate dual port ram */
+ dpaddr = dpram_alloc_align(
+ (NUM_RX_BDS * sizeof(I2C_BD)) + (NUM_TX_BDS * sizeof(I2C_BD)) +
+ MAX_TX_SPACE, 8);
+ }
+#else
+ dpaddr = CPM_I2C_BASE;
+#endif
+
+ /*
+ * initialise data in dual port ram:
+ *
+ * dpaddr->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)
+ */
+
+ rbase = dpaddr;
+ tbase = rbase + NUM_RX_BDS * sizeof(I2C_BD);
+
+ /* Initialize Port B I2C pins. */
+ cp->cp_pbpar |= 0x00000030;
+ cp->cp_pbdir |= 0x00000030;
+ cp->cp_pbodr |= 0x00000030;
+
+ /* Disable interrupts */
+ i2c->i2c_i2mod = 0x00;
+ i2c->i2c_i2cmr = 0x00;
+ i2c->i2c_i2cer = 0xff;
+ i2c->i2c_i2add = slaveaddr;
+
+ /*
+ * 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)
+ */
+ PRINTD(("[I2C] Setting rate...\n"));
+ i2c_setrate (gd->cpu_clk, CONFIG_SYS_I2C_SPEED) ;
+
+ /* Set I2C controller in master mode */
+ i2c->i2c_i2com = 0x01;
+
+ /* Set SDMA bus arbitration level to 5 (SDCR) */
+ immap->im_siu_conf.sc_sdcr = 0x0001 ;
+
+ /* Initialize Tx/Rx parameters */
+ iip->iic_rbase = rbase;
+ iip->iic_tbase = tbase;
+ rxbd = (I2C_BD *)((unsigned char *)&cp->cp_dpmem[iip->iic_rbase]);
+ txbd = (I2C_BD *)((unsigned char *)&cp->cp_dpmem[iip->iic_tbase]);
+
+ PRINTD(("[I2C] rbase = %04x\n", iip->iic_rbase));
+ PRINTD(("[I2C] tbase = %04x\n", iip->iic_tbase));
+ PRINTD(("[I2C] rxbd = %08x\n", (int)rxbd));
+ PRINTD(("[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;
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+ /*
+ * Initialize required parameters if using microcode patch.
+ */
+ iip->iic_rbptr = iip->iic_rbase;
+ iip->iic_tbptr = iip->iic_tbase;
+ iip->iic_rstate = 0;
+ iip->iic_tstate = 0;
+#else
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ do {
+ __asm__ __volatile__ ("eieio");
+ } while (cp->cp_cpcr & CPM_CR_FLG);
+#endif
+
+ /* 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 cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm;
+ volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+
+ PRINTD(("[I2C] i2c_newio\n"));
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+ iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#endif
+ state->rx_idx = 0;
+ state->tx_idx = 0;
+ state->rxbd = (void*)&cp->cp_dpmem[iip->iic_rbase];
+ state->txbd = (void*)&cp->cp_dpmem[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;
+
+ PRINTD(("[I2C] rxbd = %08x\n", (int)state->rxbd));
+ PRINTD(("[I2C] txbd = %08x\n", (int)state->txbd));
+ PRINTD(("[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;
+
+ PRINTD(("[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;
+
+ PRINTD(("[I2C] txbd = %08x\n", (int)txbd));
+
+ if (flags & I2CF_START_COND) {
+ PRINTD(("[I2C] Formatting addresses...\n"));
+ if (flags & I2CF_ENABLE_SECONDARY) {
+ txbd->length = size + 2; /* Length of msg + dest addr */
+ txbd->addr[0] = address << 1;
+ txbd->addr[1] = secondary_address;
+ i = 2;
+ } else {
+ txbd->length = size + 1; /* Length of msg + dest addr */
+ txbd->addr[0] = address << 1; /* Write dest addr to BD */
+ 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 */
+ PRINTD(("[I2C] copy data...\n"));
+ for(j = 0; j < size; i++, j++)
+ txbd->addr[i] = dataout[j];
+
+ PRINTD(("[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;
+
+ PRINTD(("[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;
+
+ PRINTD(("[I2C] rxbd = %08x\n", (int)rxbd));
+ PRINTD(("[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;
+ }
+
+ PRINTD(("[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]));
+ PRINTD(("[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 cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm;
+ volatile i2c8xx_t *i2c = (i2c8xx_t *)&immap->im_i2c;
+ volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+ volatile I2C_BD *txbd, *rxbd;
+ volatile int j = 0;
+
+ PRINTD(("[I2C] i2c_doio\n"));
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+ iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#endif
+
+ if (state->tx_idx <= 0 && state->rx_idx <= 0) {
+ PRINTD(("[I2C] No I/O is queued\n"));
+ return I2CERR_QUEUE_EMPTY;
+ }
+
+ iip->iic_rbptr = iip->iic_rbase;
+ iip->iic_tbptr = iip->iic_tbase;
+
+ /* Enable I2C */
+ PRINTD(("[I2C] Enabling I2C...\n"));
+ i2c->i2c_i2mod |= 0x01;
+
+ /* Begin transmission */
+ i2c->i2c_i2com |= 0x80;
+
+ /* Loop until transmit & receive completed */
+
+ if (state->tx_idx > 0) {
+ txbd = ((I2C_BD*)state->txbd) - 1;
+ PRINTD(("[I2C] Transmitting...(txbd=0x%08lx)\n", (ulong)txbd));
+ while((txbd->status & BD_SC_READY) && (j++ < TOUT_LOOP)) {
+ if (ctrlc()) {
+ return (-1);
+ }
+ __asm__ __volatile__ ("eieio");
+ }
+ }
+
+ if ((state->rx_idx > 0) && (j < TOUT_LOOP)) {
+ rxbd = ((I2C_BD*)state->rxbd) - 1;
+ PRINTD(("[I2C] Receiving...(rxbd=0x%08lx)\n", (ulong)rxbd));
+ while((rxbd->status & BD_SC_EMPTY) && (j++ < TOUT_LOOP)) {
+ if (ctrlc()) {
+ return (-1);
+ }
+ __asm__ __volatile__ ("eieio");
+ }
+ }
+
+ /* Turn off I2C */
+ i2c->i2c_i2mod &= ~0x01;
+
+ if (state->err_cb != NULL) {
+ int n, i, b;
+
+ /*
+ * if we have an error callback function, look at the
+ * error bits in the bd status and pass them back
+ */
+
+ if ((n = state->tx_idx) > 0) {
+ for (i = 0; i < n; i++) {
+ txbd = ((I2C_BD*)state->txbd) - (n - i);
+ if ((b = txbd->status & BD_I2C_TX_ERR) != 0)
+ (*state->err_cb)(I2CECB_TX_ERR|b, i);
+ }
+ }
+
+ if ((n = state->rx_idx) > 0) {
+ for (i = 0; i < n; i++) {
+ rxbd = ((I2C_BD*)state->rxbd) - (n - i);
+ if ((b = rxbd->status & BD_I2C_RX_ERR) != 0)
+ (*state->err_cb)(I2CECB_RX_ERR|b, i);
+ }
+ }
+
+ if (j >= TOUT_LOOP)
+ (*state->err_cb)(I2CECB_TIMEOUT, 0);
+ }
+
+ return (j >= TOUT_LOOP) ? I2CERR_TIMEOUT : 0;
+}
+
+static int had_tx_nak;
+
+static void
+i2c_test_callback(int flags, int xnum)
+{
+ if ((flags & I2CECB_TX_ERR) && (flags & I2CECB_TX_NAK))
+ had_tx_nak = 1;
+}
+
+int i2c_probe(uchar chip)
+{
+ i2c_state_t state;
+ int rc;
+ uchar buf[1];
+
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+ i2c_newio(&state);
+
+ state.err_cb = i2c_test_callback;
+ had_tx_nak = 0;
+
+ rc = i2c_receive(&state, chip, 0, I2CF_START_COND|I2CF_STOP_COND, 1, buf);
+
+ if (rc != 0)
+ return (rc);
+
+ rc = i2c_doio(&state);
+
+ if ((rc != 0) && (rc != I2CERR_TIMEOUT))
+ return (rc);
+
+ return (had_tx_nak);
+}
+
+int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ i2c_state_t state;
+ uchar xaddr[4];
+ int rc;
+
+#ifdef CONFIG_LWMON
+ WATCHDOG_RESET();
+#endif
+
+ 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) {
+ if (gd->have_console)
+ 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) {
+ if (gd->have_console)
+ printf("i2c_read: i2c_receive failed (%d)\n", rc);
+ return 1;
+ }
+
+ rc = i2c_doio(&state);
+ if (rc != 0) {
+ if (gd->have_console)
+ 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) {
+ if (gd->have_console)
+ 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) {
+ if (gd->have_console)
+ printf("i2c_write: second i2c_send failed (%d)\n", rc);
+ return 1;
+ }
+
+ rc = i2c_doio(&state);
+ if (rc != 0) {
+ if (gd->have_console)
+ printf("i2c_write: i2c_doio failed (%d)\n", rc);
+ return 1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/arch/powerpc/cpu/mpc8xx/interrupts.c b/arch/powerpc/cpu/mpc8xx/interrupts.c
new file mode 100644
index 0000000..5daa6b2
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/interrupts.c
@@ -0,0 +1,294 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <mpc8xx_irq.h>
+#include <asm/processor.h>
+#include <commproc.h>
+
+/************************************************************************/
+
+/*
+ * CPM interrupt vector functions.
+ */
+struct interrupt_action {
+ interrupt_handler_t *handler;
+ void *arg;
+};
+
+static struct interrupt_action cpm_vecs[CPMVEC_NR];
+static struct interrupt_action irq_vecs[NR_IRQS];
+
+static void cpm_interrupt_init (void);
+static void cpm_interrupt (void *regs);
+
+/************************************************************************/
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ *decrementer_count = get_tbclk () / CONFIG_SYS_HZ;
+
+ /* disable all interrupts */
+ immr->im_siu_conf.sc_simask = 0;
+
+ /* Configure CPM interrupts */
+ cpm_interrupt_init ();
+
+ return (0);
+}
+
+/************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ int irq;
+ ulong simask, newmask;
+ ulong vec, v_bit;
+
+ /*
+ * read the SIVEC register and shift the bits down
+ * to get the irq number
+ */
+ vec = immr->im_siu_conf.sc_sivec;
+ irq = vec >> 26;
+ v_bit = 0x80000000UL >> irq;
+
+ /*
+ * Read Interrupt Mask Register and Mask Interrupts
+ */
+ simask = immr->im_siu_conf.sc_simask;
+ newmask = simask & (~(0xFFFF0000 >> irq));
+ immr->im_siu_conf.sc_simask = newmask;
+
+ if (!(irq & 0x1)) { /* External Interrupt ? */
+ ulong siel;
+
+ /*
+ * Read Interrupt Edge/Level Register
+ */
+ siel = immr->im_siu_conf.sc_siel;
+
+ if (siel & v_bit) { /* edge triggered interrupt ? */
+ /*
+ * Rewrite SIPEND Register to clear interrupt
+ */
+ immr->im_siu_conf.sc_sipend = v_bit;
+ }
+ }
+
+ if (irq_vecs[irq].handler != NULL) {
+ irq_vecs[irq].handler (irq_vecs[irq].arg);
+ } else {
+ printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
+ irq, vec);
+ /* turn off the bogus interrupt to avoid it from now */
+ simask &= ~v_bit;
+ }
+ /*
+ * Re-Enable old Interrupt Mask
+ */
+ immr->im_siu_conf.sc_simask = simask;
+}
+
+/************************************************************************/
+
+/*
+ * CPM interrupt handler
+ */
+static void cpm_interrupt (void *regs)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ uint vec;
+
+ /*
+ * Get the vector by setting the ACK bit
+ * and then reading the register.
+ */
+ immr->im_cpic.cpic_civr = 1;
+ vec = immr->im_cpic.cpic_civr;
+ vec >>= 11;
+
+ if (cpm_vecs[vec].handler != NULL) {
+ (*cpm_vecs[vec].handler) (cpm_vecs[vec].arg);
+ } else {
+ immr->im_cpic.cpic_cimr &= ~(1 << vec);
+ printf ("Masking bogus CPM interrupt vector 0x%x\n", vec);
+ }
+ /*
+ * After servicing the interrupt,
+ * we have to remove the status indicator.
+ */
+ immr->im_cpic.cpic_cisr |= (1 << vec);
+}
+
+/*
+ * The CPM can generate the error interrupt when there is a race
+ * condition between generating and masking interrupts. All we have
+ * to do is ACK it and return. This is a no-op function so we don't
+ * need any special tests in the interrupt handler.
+ */
+static void cpm_error_interrupt (void *dummy)
+{
+}
+
+/************************************************************************/
+/*
+ * Install and free an interrupt handler
+ */
+void irq_install_handler (int vec, interrupt_handler_t * handler,
+ void *arg)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ if ((vec & CPMVEC_OFFSET) != 0) {
+ /* CPM interrupt */
+ vec &= 0xffff;
+ if (cpm_vecs[vec].handler != NULL) {
+ printf ("CPM interrupt 0x%x replacing 0x%x\n",
+ (uint) handler,
+ (uint) cpm_vecs[vec].handler);
+ }
+ cpm_vecs[vec].handler = handler;
+ cpm_vecs[vec].arg = arg;
+ immr->im_cpic.cpic_cimr |= (1 << vec);
+#if 0
+ printf ("Install CPM interrupt for vector %d ==> %p\n",
+ vec, handler);
+#endif
+ } else {
+ /* SIU interrupt */
+ if (irq_vecs[vec].handler != NULL) {
+ printf ("SIU interrupt %d 0x%x replacing 0x%x\n",
+ vec,
+ (uint) handler,
+ (uint) cpm_vecs[vec].handler);
+ }
+ irq_vecs[vec].handler = handler;
+ irq_vecs[vec].arg = arg;
+ immr->im_siu_conf.sc_simask |= 1 << (31 - vec);
+#if 0
+ printf ("Install SIU interrupt for vector %d ==> %p\n",
+ vec, handler);
+#endif
+ }
+}
+
+void irq_free_handler (int vec)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ if ((vec & CPMVEC_OFFSET) != 0) {
+ /* CPM interrupt */
+ vec &= 0xffff;
+#if 0
+ printf ("Free CPM interrupt for vector %d ==> %p\n",
+ vec, cpm_vecs[vec].handler);
+#endif
+ immr->im_cpic.cpic_cimr &= ~(1 << vec);
+ cpm_vecs[vec].handler = NULL;
+ cpm_vecs[vec].arg = NULL;
+ } else {
+ /* SIU interrupt */
+#if 0
+ printf ("Free CPM interrupt for vector %d ==> %p\n",
+ vec, cpm_vecs[vec].handler);
+#endif
+ immr->im_siu_conf.sc_simask &= ~(1 << (31 - vec));
+ irq_vecs[vec].handler = NULL;
+ irq_vecs[vec].arg = NULL;
+ }
+}
+
+/************************************************************************/
+
+static void cpm_interrupt_init (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ /*
+ * Initialize the CPM interrupt controller.
+ */
+
+ immr->im_cpic.cpic_cicr =
+ (CICR_SCD_SCC4 |
+ CICR_SCC_SCC3 |
+ CICR_SCB_SCC2 |
+ CICR_SCA_SCC1) | ((CPM_INTERRUPT / 2) << 13) | CICR_HP_MASK;
+
+ immr->im_cpic.cpic_cimr = 0;
+
+ /*
+ * Install the error handler.
+ */
+ irq_install_handler (CPMVEC_ERROR, cpm_error_interrupt, NULL);
+
+ immr->im_cpic.cpic_cicr |= CICR_IEN;
+
+ /*
+ * Install the cpm interrupt handler
+ */
+ irq_install_handler (CPM_INTERRUPT, cpm_interrupt, NULL);
+}
+
+/************************************************************************/
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * Trivial implementation - no need to be really accurate.
+ */
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+#if 0
+ printf ("*** Timer Interrupt *** ");
+#endif
+ /* Reset Timer Expired and Timers Interrupt Status */
+ immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+ __asm__ ("nop");
+ /*
+ Clear TEXPS (and TMIST on older chips). SPLSS (on older
+ chips) is cleared too.
+
+ Bitwise OR is a read-modify-write operation so ALL bits
+ which are cleared by writing `1' would be cleared by
+ operations like
+
+ immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS;
+
+ The same can be achieved by simple writing of the PLPRCR
+ to itself. If a bit value should be preserved, read the
+ register, ZERO the bit and write, not OR, the result back.
+ */
+ immr->im_clkrst.car_plprcr = immr->im_clkrst.car_plprcr;
+}
+
+/************************************************************************/
diff --git a/arch/powerpc/cpu/mpc8xx/kgdb.S b/arch/powerpc/cpu/mpc8xx/kgdb.S
new file mode 100644
index 0000000..2cc8fe6
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/kgdb.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2000 Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <command.h>
+#include <mpc8xx.h>
+#include <version.h>
+
+#define CONFIG_8xx 1 /* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#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:
+ lis r3, IDC_INVALL@h
+ mtspr DC_CST, r3
+ sync
+ lis r3, IDC_INVALL@h
+ mtspr IC_CST, r3
+ SYNC
+ 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
diff --git a/arch/powerpc/cpu/mpc8xx/lcd.c b/arch/powerpc/cpu/mpc8xx/lcd.c
new file mode 100644
index 0000000..4b88b21
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/lcd.c
@@ -0,0 +1,621 @@
+/*
+ * (C) Copyright 2001-2002
+ * Wolfgang Denk, DENX Software Engineering -- wd@denx.de
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/************************************************************************/
+/* ** HEADER FILES */
+/************************************************************************/
+
+/* #define DEBUG */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <watchdog.h>
+#include <version.h>
+#include <stdarg.h>
+#include <lcdvideo.h>
+#include <linux/types.h>
+#include <stdio_dev.h>
+#if defined(CONFIG_POST)
+#include <post.h>
+#endif
+#include <lcd.h>
+
+#ifdef CONFIG_LCD
+
+/************************************************************************/
+/* ** CONFIG STUFF -- should be moved to board config file */
+/************************************************************************/
+#ifndef CONFIG_LCD_INFO
+#define CONFIG_LCD_INFO /* Display Logo, (C) and system info */
+#endif
+
+#if defined(CONFIG_V37) || defined(CONFIG_EDT32F10)
+#undef CONFIG_LCD_LOGO
+#undef CONFIG_LCD_INFO
+#endif
+
+/*----------------------------------------------------------------------*/
+#ifdef CONFIG_KYOCERA_KCS057QV1AJ
+/*
+ * Kyocera KCS057QV1AJ-G23. Passive, color, single scan.
+ */
+#define LCD_BPP LCD_COLOR4
+
+vidinfo_t panel_info = {
+ 640, 480, 132, 99, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH,
+ LCD_BPP, 1, 0, 1, 0, 5, 0, 0, 0
+ /* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_KYOCERA_KCS057QV1AJ */
+/*----------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------*/
+#ifdef CONFIG_HITACHI_SP19X001_Z1A
+/*
+ * Hitachi SP19X001-. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+ 640, 480, 154, 116, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH,
+ LCD_COLOR8, 1, 0, 1, 0, 0, 0, 0, 0
+ /* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_HITACHI_SP19X001_Z1A */
+/*----------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------*/
+#ifdef CONFIG_NEC_NL6448AC33
+/*
+ * NEC NL6448AC33-18. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+ 640, 480, 132, 99, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+ 3, 0, 0, 1, 1, 144, 2, 0, 33
+ /* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_NEC_NL6448AC33 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_NEC_NL6448BC20
+/*
+ * NEC NL6448BC20-08. 6.5", 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+ 640, 480, 132, 99, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+ 3, 0, 0, 1, 1, 144, 2, 0, 33
+ /* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_NEC_NL6448BC20 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_NEC_NL6448BC33_54
+/*
+ * NEC NL6448BC33-54. 10.4", 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+ 640, 480, 212, 158, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+ 3, 0, 0, 1, 1, 144, 2, 0, 33
+ /* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_NEC_NL6448BC33_54 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_SHARP_LQ104V7DS01
+/*
+ * SHARP LQ104V7DS01. 6.5", 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+ 640, 480, 132, 99, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_LOW,
+ 3, 0, 0, 1, 1, 25, 1, 0, 33
+ /* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_SHARP_LQ104V7DS01 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_SHARP_16x9
+/*
+ * Sharp 320x240. Active, color, single scan. It isn't 16x9, and I am
+ * not sure what it is.......
+ */
+vidinfo_t panel_info = {
+ 320, 240, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH,
+ 3, 0, 0, 1, 1, 15, 4, 0, 3
+};
+#endif /* CONFIG_SHARP_16x9 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_SHARP_LQ057Q3DC02
+/*
+ * Sharp LQ057Q3DC02 display. Active, color, single scan.
+ */
+#undef LCD_DF
+#define LCD_DF 12
+
+vidinfo_t panel_info = {
+ 320, 240, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+ 3, 0, 0, 1, 1, 15, 4, 0, 3
+ /* wbl, vpw, lcdac, wbf */
+};
+#define CONFIG_LCD_INFO_BELOW_LOGO
+#endif /* CONFIG_SHARP_LQ057Q3DC02 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_SHARP_LQ64D341
+/*
+ * Sharp LQ64D341 display, 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+ 640, 480, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+ 3, 0, 0, 1, 1, 128, 16, 0, 32
+ /* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_SHARP_LQ64D341 */
+
+#ifdef CONFIG_SHARP_LQ065T9DR51U
+/*
+ * Sharp LQ065T9DR51U display, 400x240. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+ 400, 240, 143, 79, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH,
+ 3, 0, 0, 1, 1, 248, 4, 0, 35
+ /* wbl, vpw, lcdac, wbf */
+};
+#define CONFIG_LCD_INFO_BELOW_LOGO
+#endif /* CONFIG_SHARP_LQ065T9DR51U */
+
+#ifdef CONFIG_SHARP_LQ084V1DG21
+/*
+ * Sharp LQ084V1DG21 display, 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+ 640, 480, 171, 129, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_LOW,
+ 3, 0, 0, 1, 1, 160, 3, 0, 48
+ /* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_SHARP_LQ084V1DG21 */
+
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_HLD1045
+/*
+ * HLD1045 display, 640x480. Active, color, single scan.
+ */
+vidinfo_t panel_info = {
+ 640, 480, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+ 3, 0, 0, 1, 1, 160, 3, 0, 48
+ /* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_HLD1045 */
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_PRIMEVIEW_V16C6448AC
+/*
+ * Prime View V16C6448AC
+ */
+vidinfo_t panel_info = {
+ 640, 480, 130, 98, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW, CONFIG_SYS_LOW, CONFIG_SYS_HIGH,
+ 3, 0, 0, 1, 1, 144, 2, 0, 35
+ /* wbl, vpw, lcdac, wbf */
+};
+#endif /* CONFIG_PRIMEVIEW_V16C6448AC */
+
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_OPTREX_BW
+/*
+ * Optrex CBL50840-2 NF-FW 99 22 M5
+ * or
+ * Hitachi LMG6912RPFC-00T
+ * or
+ * Hitachi SP14Q002
+ *
+ * 320x240. Black & white.
+ */
+#define OPTREX_BPP 0 /* 0 - monochrome, 1 bpp */
+ /* 1 - 4 grey levels, 2 bpp */
+ /* 2 - 16 grey levels, 4 bpp */
+vidinfo_t panel_info = {
+ 320, 240, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW,
+ OPTREX_BPP, 0, 0, 0, 0, 0, 0, 0, 0, 4
+};
+#endif /* CONFIG_OPTREX_BW */
+
+/*-----------------------------------------------------------------*/
+#ifdef CONFIG_EDT32F10
+/*
+ * Emerging Display Technologies 320x240. Passive, monochrome, single scan.
+ */
+#define LCD_BPP LCD_MONOCHROME
+#define LCD_DF 10
+
+vidinfo_t panel_info = {
+ 320, 240, 0, 0, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_HIGH, CONFIG_SYS_LOW,
+ LCD_BPP, 0, 0, 0, 0, 33, 0, 0, 0
+};
+#endif
+/*----------------------------------------------------------------------*/
+
+
+int lcd_line_length;
+
+int lcd_color_fg;
+int lcd_color_bg;
+
+/*
+ * Frame buffer memory information
+ */
+void *lcd_base; /* Start of framebuffer memory */
+void *lcd_console_address; /* Start of console buffer */
+
+short console_col;
+short console_row;
+
+/************************************************************************/
+
+void lcd_ctrl_init (void *lcdbase);
+void lcd_enable (void);
+#if LCD_BPP == LCD_COLOR8
+void lcd_setcolreg (ushort regno,
+ ushort red, ushort green, ushort blue);
+#endif
+#if LCD_BPP == LCD_MONOCHROME
+void lcd_initcolregs (void);
+#endif
+
+#if defined(CONFIG_RBC823)
+void lcd_disable (void);
+#endif
+
+/************************************************************************/
+
+/************************************************************************/
+/* ----------------- chipset specific functions ----------------------- */
+/************************************************************************/
+
+/*
+ * Calculate fb size for VIDEOLFB_ATAG.
+ */
+ulong calc_fbsize (void)
+{
+ ulong size;
+ int line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+
+ size = line_length * panel_info.vl_row;
+
+ return size;
+}
+
+void lcd_ctrl_init (void *lcdbase)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile lcd823_t *lcdp = &immr->im_lcd;
+
+ uint lccrtmp;
+ uint lchcr_hpc_tmp;
+
+ /* Initialize the LCD control register according to the LCD
+ * parameters defined. We do everything here but enable
+ * the controller.
+ */
+
+#ifdef CONFIG_RPXLITE
+ /* This is special for RPXlite_DW Software Development Platform **[Sam]** */
+ panel_info.vl_dp = CONFIG_SYS_LOW;
+#endif
+
+ lccrtmp = LCDBIT (LCCR_BNUM_BIT,
+ (((panel_info.vl_row * panel_info.vl_col) * (1 << LCD_BPP)) / 128));
+
+ lccrtmp |= LCDBIT (LCCR_CLKP_BIT, panel_info.vl_clkp) |
+ LCDBIT (LCCR_OEP_BIT, panel_info.vl_oep) |
+ LCDBIT (LCCR_HSP_BIT, panel_info.vl_hsp) |
+ LCDBIT (LCCR_VSP_BIT, panel_info.vl_vsp) |
+ LCDBIT (LCCR_DP_BIT, panel_info.vl_dp) |
+ LCDBIT (LCCR_BPIX_BIT, panel_info.vl_bpix) |
+ LCDBIT (LCCR_LBW_BIT, panel_info.vl_lbw) |
+ LCDBIT (LCCR_SPLT_BIT, panel_info.vl_splt) |
+ LCDBIT (LCCR_CLOR_BIT, panel_info.vl_clor) |
+ LCDBIT (LCCR_TFT_BIT, panel_info.vl_tft);
+
+#if 0
+ lccrtmp |= ((SIU_LEVEL5 / 2) << 12);
+ lccrtmp |= LCCR_EIEN;
+#endif
+
+ lcdp->lcd_lccr = lccrtmp;
+ lcdp->lcd_lcsr = 0xFF; /* Clear pending interrupts */
+
+ /* Initialize LCD controller bus priorities.
+ */
+#ifdef CONFIG_RBC823
+ immr->im_siu_conf.sc_sdcr = (immr->im_siu_conf.sc_sdcr & ~0x0f) | 1; /* RAID = 01, LAID = 00 */
+#else
+ immr->im_siu_conf.sc_sdcr &= ~0x0f; /* RAID = LAID = 0 */
+
+ /* set SHFT/CLOCK division factor 4
+ * This needs to be set based upon display type and processor
+ * speed. The TFT displays run about 20 to 30 MHz.
+ * I was running 64 MHz processor speed.
+ * The value for this divider must be chosen so the result is
+ * an integer of the processor speed (i.e., divide by 3 with
+ * 64 MHz would be bad).
+ */
+ immr->im_clkrst.car_sccr &= ~0x1F;
+ immr->im_clkrst.car_sccr |= LCD_DF; /* was 8 */
+
+#endif /* CONFIG_RBC823 */
+
+#if defined(CONFIG_RBC823)
+ /* Enable LCD on port D.
+ */
+ immr->im_ioport.iop_pddat &= 0x0300;
+ immr->im_ioport.iop_pdpar |= 0x1CFF;
+ immr->im_ioport.iop_pddir |= 0x1CFF;
+
+ /* Configure LCD_ON, VEE_ON, CCFL_ON on port B.
+ */
+ immr->im_cpm.cp_pbdat &= ~0x00005001;
+ immr->im_cpm.cp_pbpar &= ~0x00005001;
+ immr->im_cpm.cp_pbdir |= 0x00005001;
+#elif !defined(CONFIG_EDT32F10)
+ /* Enable LCD on port D.
+ */
+ immr->im_ioport.iop_pdpar |= 0x1FFF;
+ immr->im_ioport.iop_pddir |= 0x1FFF;
+
+ /* Enable LCD_A/B/C on port B.
+ */
+ immr->im_cpm.cp_pbpar |= 0x00005001;
+ immr->im_cpm.cp_pbdir |= 0x00005001;
+#else
+ /* Enable LCD on port D.
+ */
+ immr->im_ioport.iop_pdpar |= 0x1DFF;
+ immr->im_ioport.iop_pdpar &= ~0x0200;
+ immr->im_ioport.iop_pddir |= 0x1FFF;
+ immr->im_ioport.iop_pddat |= 0x0200;
+#endif
+
+ /* Load the physical address of the linear frame buffer
+ * into the LCD controller.
+ * BIG NOTE: This has to be modified to load A and B depending
+ * upon the split mode of the LCD.
+ */
+ lcdp->lcd_lcfaa = (ulong)lcd_base;
+ lcdp->lcd_lcfba = (ulong)lcd_base;
+
+ /* MORE HACKS...This must be updated according to 823 manual
+ * for different panels.
+ * Udi Finkelstein - done - see below:
+ * Note: You better not try unsupported combinations such as
+ * 4-bit wide passive dual scan LCD at 4/8 Bit color.
+ */
+ lchcr_hpc_tmp =
+ (panel_info.vl_col *
+ (panel_info.vl_tft ? 8 :
+ (((2 - panel_info.vl_lbw) << /* 4 bit=2, 8-bit = 1 */
+ /* use << to mult by: single scan = 1, dual scan = 2 */
+ panel_info.vl_splt) *
+ (panel_info.vl_bpix | 1)))) >> 3; /* 2/4 BPP = 1, 8/16 BPP = 3 */
+
+ lcdp->lcd_lchcr = LCHCR_BO |
+ LCDBIT (LCHCR_AT_BIT, 4) |
+ LCDBIT (LCHCR_HPC_BIT, lchcr_hpc_tmp) |
+ panel_info.vl_wbl;
+
+ lcdp->lcd_lcvcr = LCDBIT (LCVCR_VPW_BIT, panel_info.vl_vpw) |
+ LCDBIT (LCVCR_LCD_AC_BIT, panel_info.vl_lcdac) |
+ LCDBIT (LCVCR_VPC_BIT, panel_info.vl_row) |
+ panel_info.vl_wbf;
+
+}
+
+/*----------------------------------------------------------------------*/
+
+#ifdef NOT_USED_SO_FAR
+static void
+lcd_getcolreg (ushort regno, ushort *red, ushort *green, ushort *blue)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = &(immr->im_cpm);
+ unsigned short colreg, *cmap_ptr;
+
+ cmap_ptr = (unsigned short *)&cp->lcd_cmap[regno * 2];
+
+ colreg = *cmap_ptr;
+#ifdef CONFIG_SYS_INVERT_COLORS
+ colreg ^= 0x0FFF;
+#endif
+
+ *red = (colreg >> 8) & 0x0F;
+ *green = (colreg >> 4) & 0x0F;
+ *blue = colreg & 0x0F;
+}
+#endif /* NOT_USED_SO_FAR */
+
+/*----------------------------------------------------------------------*/
+
+#if LCD_BPP == LCD_COLOR8
+void
+lcd_setcolreg (ushort regno, ushort red, ushort green, ushort blue)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = &(immr->im_cpm);
+ unsigned short colreg, *cmap_ptr;
+
+ cmap_ptr = (unsigned short *)&cp->lcd_cmap[regno * 2];
+
+ colreg = ((red & 0x0F) << 8) |
+ ((green & 0x0F) << 4) |
+ (blue & 0x0F) ;
+#ifdef CONFIG_SYS_INVERT_COLORS
+ colreg ^= 0x0FFF;
+#endif
+ *cmap_ptr = colreg;
+
+ debug ("setcolreg: reg %2d @ %p: R=%02X G=%02X B=%02X => %02X%02X\n",
+ regno, &(cp->lcd_cmap[regno * 2]),
+ red, green, blue,
+ cp->lcd_cmap[ regno * 2 ], cp->lcd_cmap[(regno * 2) + 1]);
+}
+#endif /* LCD_COLOR8 */
+
+/*----------------------------------------------------------------------*/
+
+#if LCD_BPP == LCD_MONOCHROME
+static
+void lcd_initcolregs (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = &(immr->im_cpm);
+ ushort regno;
+
+ for (regno = 0; regno < 16; regno++) {
+ cp->lcd_cmap[regno * 2] = 0;
+ cp->lcd_cmap[(regno * 2) + 1] = regno & 0x0f;
+ }
+}
+#endif
+
+/*----------------------------------------------------------------------*/
+
+void lcd_enable (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile lcd823_t *lcdp = &immr->im_lcd;
+
+ /* Enable the LCD panel */
+#ifndef CONFIG_RBC823
+ immr->im_siu_conf.sc_sdcr |= (1 << (31 - 25)); /* LAM = 1 */
+#endif
+ lcdp->lcd_lccr |= LCCR_PON;
+
+#ifdef CONFIG_V37
+ /* Turn on display backlight */
+ immr->im_cpm.cp_pbpar |= 0x00008000;
+ immr->im_cpm.cp_pbdir |= 0x00008000;
+#elif defined(CONFIG_RBC823)
+ /* Turn on display backlight */
+ immr->im_cpm.cp_pbdat |= 0x00004000;
+#endif
+
+#if defined(CONFIG_LWMON)
+ { uchar c = pic_read (0x60);
+#if defined(CONFIG_LCD) && defined(CONFIG_LWMON) && (CONFIG_POST & CONFIG_SYS_POST_SYSMON)
+ /* Enable LCD later in sysmon test, only if temperature is OK */
+#else
+ c |= 0x07; /* Power on CCFL, Enable CCFL, Chip Enable LCD */
+#endif
+ pic_write (0x60, c);
+ }
+#endif /* CONFIG_LWMON */
+
+#if defined(CONFIG_R360MPI)
+ {
+ extern void r360_i2c_lcd_write (uchar data0, uchar data1);
+ unsigned long bgi, ctr;
+ char *p;
+
+ if ((p = getenv("lcdbgi")) != NULL) {
+ bgi = simple_strtoul (p, 0, 10) & 0xFFF;
+ } else {
+ bgi = 0xFFF;
+ }
+
+ if ((p = getenv("lcdctr")) != NULL) {
+ ctr = simple_strtoul (p, 0, 10) & 0xFFF;
+ } else {
+ ctr=0x7FF;
+ }
+
+ r360_i2c_lcd_write(0x10, 0x01);
+ r360_i2c_lcd_write(0x20, 0x01);
+ r360_i2c_lcd_write(0x30 | ((bgi>>8) & 0xF), bgi & 0xFF);
+ r360_i2c_lcd_write(0x40 | ((ctr>>8) & 0xF), ctr & 0xFF);
+ }
+#endif /* CONFIG_R360MPI */
+#ifdef CONFIG_RBC823
+ udelay(200000); /* wait 200ms */
+ /* Turn VEE_ON first */
+ immr->im_cpm.cp_pbdat |= 0x00000001;
+ udelay(200000); /* wait 200ms */
+ /* Now turn on LCD_ON */
+ immr->im_cpm.cp_pbdat |= 0x00001000;
+#endif
+#ifdef CONFIG_RRVISION
+ debug ("PC4->Output(1): enable LVDS\n");
+ debug ("PC5->Output(0): disable PAL clock\n");
+ immr->im_ioport.iop_pddir |= 0x1000;
+ immr->im_ioport.iop_pcpar &= ~(0x0C00);
+ immr->im_ioport.iop_pcdir |= 0x0C00 ;
+ immr->im_ioport.iop_pcdat |= 0x0800 ;
+ immr->im_ioport.iop_pcdat &= ~(0x0400);
+ debug ("PDPAR=0x%04X PDDIR=0x%04X PDDAT=0x%04X\n",
+ immr->im_ioport.iop_pdpar,
+ immr->im_ioport.iop_pddir,
+ immr->im_ioport.iop_pddat);
+ debug ("PCPAR=0x%04X PCDIR=0x%04X PCDAT=0x%04X\n",
+ immr->im_ioport.iop_pcpar,
+ immr->im_ioport.iop_pcdir,
+ immr->im_ioport.iop_pcdat);
+#endif
+}
+
+/*----------------------------------------------------------------------*/
+
+#if defined (CONFIG_RBC823)
+void lcd_disable (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile lcd823_t *lcdp = &immr->im_lcd;
+
+#if defined(CONFIG_LWMON)
+ { uchar c = pic_read (0x60);
+ c &= ~0x07; /* Power off CCFL, Disable CCFL, Chip Disable LCD */
+ pic_write (0x60, c);
+ }
+#elif defined(CONFIG_R360MPI)
+ {
+ extern void r360_i2c_lcd_write (uchar data0, uchar data1);
+
+ r360_i2c_lcd_write(0x10, 0x00);
+ r360_i2c_lcd_write(0x20, 0x00);
+ r360_i2c_lcd_write(0x30, 0x00);
+ r360_i2c_lcd_write(0x40, 0x00);
+ }
+#endif /* CONFIG_LWMON */
+ /* Disable the LCD panel */
+ lcdp->lcd_lccr &= ~LCCR_PON;
+#ifdef CONFIG_RBC823
+ /* Turn off display backlight, VEE and LCD_ON */
+ immr->im_cpm.cp_pbdat &= ~0x00005001;
+#else
+ immr->im_siu_conf.sc_sdcr &= ~(1 << (31 - 25)); /* LAM = 0 */
+#endif /* CONFIG_RBC823 */
+}
+#endif /* NOT_USED_SO_FAR || CONFIG_RBC823 */
+
+
+/************************************************************************/
+
+#endif /* CONFIG_LCD */
diff --git a/arch/powerpc/cpu/mpc8xx/plprcr_write.S b/arch/powerpc/cpu/mpc8xx/plprcr_write.S
new file mode 100644
index 0000000..e325671
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/plprcr_write.S
@@ -0,0 +1,135 @@
+/*
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <mpc8xx.h>
+#include <ppc_asm.tmpl>
+#include <asm/cache.h>
+
+#define CACHE_CMD_ENABLE 0x02000000
+#define CACHE_CMD_DISABLE 0x04000000
+#define CACHE_CMD_LOAD_LOCK 0x06000000
+#define CACHE_CMD_UNLOCK_LINE 0x08000000
+#define CACHE_CMD_UNLOCK_ALL 0x0A000000
+#define CACHE_CMD_INVALIDATE 0x0C000000
+#define SPEED_PLPRCR_WAIT_5CYC 150
+#define _CACHE_ALIGN_SIZE 16
+
+
+ .text
+ .align 2
+ .globl plprcr_write_866
+
+/*
+ * void plprcr_write_866 (long plprcr)
+ * Write PLPRCR, including workaround for device errata SIU4 and SIU9.
+ */
+
+plprcr_write_866:
+ mfspr r10, LR /* save the Link Register value */
+
+ /* turn instruction cache on (no MMU required for instructions)
+ */
+ lis r4, CACHE_CMD_ENABLE@h
+ ori r4, r4, CACHE_CMD_ENABLE@l
+ mtspr IC_CST, r4
+ isync
+
+ /* clear IC_CST error bits
+ */
+ mfspr r4, IC_CST
+
+ bl plprcr_here
+
+plprcr_here:
+ mflr r5
+
+ /* calculate relocation offset
+ */
+ lis r4, plprcr_here@h
+ ori r4, r4, plprcr_here@l
+ sub r5, r5, r4
+
+ /* calculate first address of this function
+ */
+ lis r6, plprcr_write_866@h
+ ori r6, r6, plprcr_write_866@l
+ add r6, r6, r5
+
+ /* calculate end address of this function
+ */
+ lis r7, plprcr_end@h
+ ori r7, r7, plprcr_end@l
+ add r7, r7, r5
+
+ /* load and lock code addresses
+ */
+ mr r5, r6
+
+plprcr_loop:
+ mtspr IC_ADR, r5
+ addi r5, r5, _CACHE_ALIGN_SIZE /* increment by one line */
+
+ lis r4, CACHE_CMD_LOAD_LOCK@h
+ ori r4, r4, CACHE_CMD_LOAD_LOCK@l
+ mtspr IC_CST, r4
+ isync
+
+ cmpw r5, r7
+ blt plprcr_loop
+
+ /* IC_CST error bits not evaluated
+ */
+
+ /* switch PLPRCR
+ */
+ mfspr r4, IMMR /* read IMMR */
+ rlwinm r4, r4, 0, 0, 15 /* only high 16 bits count */
+
+ /* write sequence according to MPC866 Errata
+ */
+ stw r3, PLPRCR(r4)
+ isync
+
+ lis r3, SPEED_PLPRCR_WAIT_5CYC@h
+ ori r3, r3, SPEED_PLPRCR_WAIT_5CYC@l
+
+plprcr_wait:
+ cmpwi r3, 0
+ beq plprcr_wait_end
+ nop
+ subi r3, r3, 1
+ b plprcr_wait
+
+plprcr_wait_end:
+
+ /* unlock instruction cache but leave it enabled
+ */
+ lis r4, CACHE_CMD_UNLOCK_ALL@h
+ ori r4, r4, CACHE_CMD_UNLOCK_ALL@l
+ mtspr IC_CST, r4
+ isync
+
+ mtspr LR, r10 /* restore original Link Register value */
+ blr
+
+plprcr_end:
diff --git a/arch/powerpc/cpu/mpc8xx/scc.c b/arch/powerpc/cpu/mpc8xx/scc.c
new file mode 100644
index 0000000..effb967
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/scc.c
@@ -0,0 +1,572 @@
+/*
+ * File: scc.c
+ * Description:
+ * Basic ET HW initialization and packet RX/TX routines
+ *
+ * NOTE <<<IMPORTANT: PLEASE READ>>>:
+ * Do not cache Rx/Tx buffers!
+ */
+
+/*
+ * MPC823 <-> MC68160 Connections:
+ *
+ * Setup MPC823 to work with MC68160 Enhanced Ethernet
+ * Serial Tranceiver as follows:
+ *
+ * MPC823 Signal MC68160 Comments
+ * ------ ------ ------- --------
+ * PA-12 ETHTX --------> TX Eth. Port Transmit Data
+ * PB-18 E_TENA --------> TENA Eth. Transmit Port Enable
+ * PA-5 ETHTCK <-------- TCLK Eth. Port Transmit Clock
+ * PA-13 ETHRX <-------- RX Eth. Port Receive Data
+ * PC-8 E_RENA <-------- RENA Eth. Receive Enable
+ * PA-6 ETHRCK <-------- RCLK Eth. Port Receive Clock
+ * PC-9 E_CLSN <-------- CLSN Eth. Port Collision Indication
+ *
+ * FADS Board Signal MC68160 Comments
+ * ----------------- ------- --------
+ * (BCSR1) ETHEN* --------> CS2 Eth. Port Enable
+ * (BSCR4) TPSQEL* --------> TPSQEL Twisted Pair Signal Quality Error Test Enable
+ * (BCSR4) TPFLDL* --------> TPFLDL Twisted Pair Full-Duplex
+ * (BCSR4) ETHLOOP --------> LOOP Eth. Port Diagnostic Loop-Back
+ *
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <commproc.h>
+#include <net.h>
+#include <command.h>
+
+#if defined(CONFIG_CMD_NET) && defined(SCC_ENET)
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH 1520
+
+#define TX_BUF_CNT 2
+
+#define TOUT_LOOP 10000 /* 10 ms to have a packet sent */
+
+static char txbuf[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 scc_send(struct eth_device* dev, volatile void *packet, int length);
+static int scc_recv(struct eth_device* dev);
+static int scc_init (struct eth_device* dev, bd_t * bd);
+static void scc_halt(struct eth_device* dev);
+
+int scc_initialize(bd_t *bis)
+{
+ struct eth_device* dev;
+
+ dev = (struct eth_device*) malloc(sizeof *dev);
+ memset(dev, 0, sizeof *dev);
+
+ sprintf(dev->name, "SCC ETHERNET");
+ dev->iobase = 0;
+ dev->priv = 0;
+ dev->init = scc_init;
+ dev->halt = scc_halt;
+ dev->send = scc_send;
+ dev->recv = scc_recv;
+
+ eth_register(dev);
+
+ return 1;
+}
+
+static int scc_send(struct eth_device* dev, volatile void *packet, int length)
+{
+ int i, j=0;
+#if 0
+ volatile char *in, *out;
+#endif
+
+ /* section 16.9.23.3
+ * Wait for ready
+ */
+#if 0
+ while (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY);
+ out = (char *)(rtx->txbd[txIdx].cbd_bufaddr);
+ in = packet;
+ for(i = 0; i < length; i++) {
+ *out++ = *in++;
+ }
+ rtx->txbd[txIdx].cbd_datlen = length;
+ rtx->txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST);
+ while (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) j++;
+
+#ifdef ET_DEBUG
+ printf("cycles: %d status: %x\n", j, rtx->txbd[txIdx].cbd_sc);
+#endif
+ i = (rtx->txbd[txIdx++].cbd_sc & BD_ENET_TX_STATS) /* return only status bits */;
+
+ /* wrap around buffer index when necessary */
+ if (txIdx >= TX_BUF_CNT) txIdx = 0;
+#endif
+
+ while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+ udelay (1); /* will also trigger Wd if needed */
+ j++;
+ }
+ if (j>=TOUT_LOOP) printf("TX not ready\n");
+ 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);
+ while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+ udelay (1); /* will also trigger Wd if needed */
+ j++;
+ }
+ if (j>=TOUT_LOOP) printf("TX timeout\n");
+#ifdef ET_DEBUG
+ printf("cycles: %d status: %x\n", j, rtx->txbd[txIdx].cbd_sc);
+#endif
+ i = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS) /* return only status bits */;
+ return i;
+}
+
+static int scc_recv (struct eth_device *dev)
+{
+ int length;
+
+ for (;;) {
+ /* section 16.9.23.2 */
+ 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) {
+#ifdef ET_DEBUG
+ printf ("err: %x\n", rtx->rxbd[rxIdx].cbd_sc);
+#endif
+ } else {
+ /* Pass the packet up to the protocol layers. */
+ NetReceive (NetRxPackets[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 scc_init (struct eth_device *dev, bd_t * bis)
+{
+
+ int i;
+ scc_enet_t *pram_ptr;
+
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+#if defined(CONFIG_LWMON)
+ reset_phy();
+#endif
+
+#ifdef CONFIG_FADS
+#if defined(CONFIG_MPC86xADS) || defined(CONFIG_MPC860T)
+ /* The MPC86xADS/FADS860T don't use the MODEM_EN or DATA_VOICE signals. */
+ *((uint *) BCSR4) &= ~BCSR4_ETHLOOP;
+ *((uint *) BCSR4) |= BCSR4_TFPLDL | BCSR4_TPSQEL;
+ *((uint *) BCSR1) &= ~BCSR1_ETHEN;
+#else
+ *((uint *) BCSR4) &= ~(BCSR4_ETHLOOP | BCSR4_MODEM_EN);
+ *((uint *) BCSR4) |= BCSR4_TFPLDL | BCSR4_TPSQEL | BCSR4_DATA_VOICE;
+ *((uint *) BCSR1) &= ~BCSR1_ETHEN;
+#endif
+#endif
+
+ pram_ptr = (scc_enet_t *) & (immr->im_cpm.cp_dparam[PROFF_ENET]);
+
+ rxIdx = 0;
+ txIdx = 0;
+
+ if (!rtx) {
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ rtx = (RTXBD *) (immr->im_cpm.cp_dpmem +
+ dpram_alloc_align (sizeof (RTXBD), 8));
+#else
+ rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_SCC_BASE);
+#endif
+ }
+
+#if (defined(PA_ENET_RXD) && defined(PA_ENET_TXD))
+ /* Configure port A pins for Txd and Rxd.
+ */
+ immr->im_ioport.iop_papar |= (PA_ENET_RXD | PA_ENET_TXD);
+ immr->im_ioport.iop_padir &= ~(PA_ENET_RXD | PA_ENET_TXD);
+ immr->im_ioport.iop_paodr &= ~PA_ENET_TXD;
+#elif (defined(PB_ENET_RXD) && defined(PB_ENET_TXD))
+ /* Configure port B pins for Txd and Rxd.
+ */
+ immr->im_cpm.cp_pbpar |= (PB_ENET_RXD | PB_ENET_TXD);
+ immr->im_cpm.cp_pbdir &= ~(PB_ENET_RXD | PB_ENET_TXD);
+ immr->im_cpm.cp_pbodr &= ~PB_ENET_TXD;
+#else
+#error Configuration Error: exactly ONE of PA_ENET_[RT]XD, PB_ENET_[RT]XD must be defined
+#endif
+
+#if defined(PC_ENET_LBK)
+ /* Configure port C pins to disable External Loopback
+ */
+ immr->im_ioport.iop_pcpar &= ~PC_ENET_LBK;
+ immr->im_ioport.iop_pcdir |= PC_ENET_LBK;
+ immr->im_ioport.iop_pcso &= ~PC_ENET_LBK;
+ immr->im_ioport.iop_pcdat &= ~PC_ENET_LBK; /* Disable Loopback */
+#endif /* PC_ENET_LBK */
+
+ /* Configure port C pins to enable CLSN and RENA.
+ */
+ immr->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+ immr->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+ immr->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA);
+
+ /* Configure port A for TCLK and RCLK.
+ */
+ immr->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK);
+ immr->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK);
+
+ /*
+ * Configure Serial Interface clock routing -- see section 16.7.5.3
+ * First, clear all SCC bits to zero, then set the ones we want.
+ */
+
+ immr->im_cpm.cp_sicr &= ~SICR_ENET_MASK;
+ immr->im_cpm.cp_sicr |= SICR_ENET_CLKRT;
+
+
+ /*
+ * Initialize SDCR -- see section 16.9.23.7
+ * SDMA configuration register
+ */
+ immr->im_siu_conf.sc_sdcr = 0x01;
+
+
+ /*
+ * Setup SCC Ethernet Parameter RAM
+ */
+
+ pram_ptr->sen_genscc.scc_rfcr = 0x18; /* Normal Operation and Mot byte ordering */
+ pram_ptr->sen_genscc.scc_tfcr = 0x18; /* Mot byte ordering, Normal access */
+
+ pram_ptr->sen_genscc.scc_mrblr = DBUF_LENGTH; /* max. ET package len 1520 */
+
+ pram_ptr->sen_genscc.scc_rbase = (unsigned int) (&rtx->rxbd[0]); /* Set RXBD tbl start at Dual Port */
+ pram_ptr->sen_genscc.scc_tbase = (unsigned int) (&rtx->txbd[0]); /* Set TXBD tbl start at Dual Port */
+
+ /*
+ * Setup Receiver Buffer Descriptors (13.14.24.18)
+ * Settings:
+ * Empty, Wrap
+ */
+
+ 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) NetRxPackets[i];
+ }
+
+ rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /*
+ * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
+ * Settings:
+ * Add PADs to Short FRAMES, Wrap, Last, Tx CRC
+ */
+
+ 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[0]);
+ }
+
+ rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /*
+ * Enter Command: Initialize Rx Params for SCC
+ */
+
+ do { /* Spin until ready to issue command */
+ __asm__ ("eieio");
+ } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+ /* Issue command */
+ immr->im_cpm.cp_cpcr =
+ ((CPM_CR_INIT_RX << 8) | (CPM_CR_ENET << 4) | CPM_CR_FLG);
+ do { /* Spin until command processed */
+ __asm__ ("eieio");
+ } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+ /*
+ * Ethernet Specific Parameter RAM
+ * see table 13-16, pg. 660,
+ * pg. 681 (example with suggested settings)
+ */
+
+ pram_ptr->sen_cpres = ~(0x0); /* Preset CRC */
+ pram_ptr->sen_cmask = 0xdebb20e3; /* Constant Mask for CRC */
+ pram_ptr->sen_crcec = 0x0; /* Error Counter CRC (unused) */
+ pram_ptr->sen_alec = 0x0; /* Alignment 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) */
+
+#define ea eth_get_dev()->enetaddr
+ 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];
+#undef ea
+
+ 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) */
+
+ /*
+ * Enter Command: Initialize Tx Params for SCC
+ */
+
+ do { /* Spin until ready to issue command */
+ __asm__ ("eieio");
+ } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+ /* Issue command */
+ immr->im_cpm.cp_cpcr =
+ ((CPM_CR_INIT_TX << 8) | (CPM_CR_ENET << 4) | CPM_CR_FLG);
+ do { /* Spin until command processed */
+ __asm__ ("eieio");
+ } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+ /*
+ * Mask all Events in SCCM - we use polling mode
+ */
+ immr->im_cpm.cp_scc[SCC_ENET].scc_sccm = 0;
+
+ /*
+ * Clear Events in SCCE -- Clear bits by writing 1's
+ */
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_scce = ~(0x0);
+
+
+ /*
+ * Initialize GSMR High 32-Bits
+ * Settings: Normal Mode
+ */
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrh = 0;
+
+ /*
+ * Initialize GSMR Low 32-Bits, but do not Enable Transmit/Receive
+ * Settings:
+ * TCI = Invert
+ * TPL = 48 bits
+ * TPP = Repeating 10's
+ * MODE = Ethernet
+ */
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl = (SCC_GSMRL_TCI |
+ SCC_GSMRL_TPL_48 |
+ SCC_GSMRL_TPP_10 |
+ SCC_GSMRL_MODE_ENET);
+
+ /*
+ * Initialize the DSR -- see section 13.14.4 (pg. 513) v0.4
+ */
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_dsr = 0xd555;
+
+ /*
+ * Initialize the PSMR
+ * Settings:
+ * CRC = 32-Bit CCITT
+ * NIB = Begin searching for SFD 22 bits after RENA
+ * FDE = Full Duplex Enable
+ * LPB = Loopback Enable (Needed when FDE is set)
+ * BRO = Reject broadcast packets
+ * PROMISCOUS = Catch all packets regardless of dest. MAC adress
+ */
+ immr->im_cpm.cp_scc[SCC_ENET].scc_psmr = SCC_PSMR_ENCRC |
+ SCC_PSMR_NIB22 |
+#if defined(CONFIG_SCC_ENET_FULL_DUPLEX)
+ SCC_PSMR_FDE | SCC_PSMR_LPB |
+#endif
+#if defined(CONFIG_SCC_ENET_NO_BROADCAST)
+ SCC_PSMR_BRO |
+#endif
+#if defined(CONFIG_SCC_ENET_PROMISCOUS)
+ SCC_PSMR_PRO |
+#endif
+ 0;
+
+ /*
+ * Configure Ethernet TENA Signal
+ */
+
+#if (defined(PC_ENET_TENA) && !defined(PB_ENET_TENA))
+ immr->im_ioport.iop_pcpar |= PC_ENET_TENA;
+ immr->im_ioport.iop_pcdir &= ~PC_ENET_TENA;
+#elif (defined(PB_ENET_TENA) && !defined(PC_ENET_TENA))
+ immr->im_cpm.cp_pbpar |= PB_ENET_TENA;
+ immr->im_cpm.cp_pbdir |= PB_ENET_TENA;
+#else
+#error Configuration Error: exactly ONE of PB_ENET_TENA, PC_ENET_TENA must be defined
+#endif
+
+#if defined(CONFIG_ADS) && defined(CONFIG_MPC860)
+ /*
+ * Port C is used to control the PHY,MC68160.
+ */
+ immr->im_ioport.iop_pcdir |=
+ (PC_ENET_ETHLOOP | PC_ENET_TPFLDL | PC_ENET_TPSQEL);
+
+ immr->im_ioport.iop_pcdat |= PC_ENET_TPFLDL;
+ immr->im_ioport.iop_pcdat &= ~(PC_ENET_ETHLOOP | PC_ENET_TPSQEL);
+ *((uint *) BCSR1) &= ~BCSR1_ETHEN;
+#endif /* MPC860ADS */
+
+#if defined(CONFIG_AMX860)
+ /*
+ * Port B is used to control the PHY,MC68160.
+ */
+ immr->im_cpm.cp_pbdir |=
+ (PB_ENET_ETHLOOP | PB_ENET_TPFLDL | PB_ENET_TPSQEL);
+
+ immr->im_cpm.cp_pbdat |= PB_ENET_TPFLDL;
+ immr->im_cpm.cp_pbdat &= ~(PB_ENET_ETHLOOP | PB_ENET_TPSQEL);
+
+ immr->im_ioport.iop_pddir |= PD_ENET_ETH_EN;
+ immr->im_ioport.iop_pddat &= ~PD_ENET_ETH_EN;
+#endif /* AMX860 */
+
+#ifdef CONFIG_RPXCLASSIC
+ *((uchar *) BCSR0) &= ~BCSR0_ETHLPBK;
+ *((uchar *) BCSR0) |= (BCSR0_ETHEN | BCSR0_COLTEST | BCSR0_FULLDPLX);
+#endif
+
+#ifdef CONFIG_RPXLITE
+ *((uchar *) BCSR0) |= BCSR0_ETHEN;
+#endif
+
+#if defined(CONFIG_QS860T)
+ /*
+ * PB27=FDE-, set output low for full duplex
+ * PB26=Link Test Enable, normally high output
+ */
+ immr->im_cpm.cp_pbdir |= 0x00000030;
+ immr->im_cpm.cp_pbdat |= 0x00000020;
+ immr->im_cpm.cp_pbdat &= ~0x00000010;
+#endif /* QS860T */
+
+#ifdef CONFIG_MBX
+ board_ether_init ();
+#endif
+
+#if defined(CONFIG_NETVIA)
+#if defined(PA_ENET_PDN)
+ immr->im_ioport.iop_papar &= ~PA_ENET_PDN;
+ immr->im_ioport.iop_padir |= PA_ENET_PDN;
+ immr->im_ioport.iop_padat |= PA_ENET_PDN;
+#elif defined(PB_ENET_PDN)
+ immr->im_cpm.cp_pbpar &= ~PB_ENET_PDN;
+ immr->im_cpm.cp_pbdir |= PB_ENET_PDN;
+ immr->im_cpm.cp_pbdat |= PB_ENET_PDN;
+#elif defined(PC_ENET_PDN)
+ immr->im_ioport.iop_pcpar &= ~PC_ENET_PDN;
+ immr->im_ioport.iop_pcdir |= PC_ENET_PDN;
+ immr->im_ioport.iop_pcdat |= PC_ENET_PDN;
+#elif defined(PD_ENET_PDN)
+ immr->im_ioport.iop_pdpar &= ~PD_ENET_PDN;
+ immr->im_ioport.iop_pddir |= PD_ENET_PDN;
+ immr->im_ioport.iop_pddat |= PD_ENET_PDN;
+#endif
+#endif
+
+ /*
+ * Set the ENT/ENR bits in the GSMR Low -- Enable Transmit/Receive
+ */
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |=
+ (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ /*
+ * Work around transmit problem with first eth packet
+ */
+#if defined (CONFIG_FADS)
+ udelay (10000); /* wait 10 ms */
+#elif defined (CONFIG_AMX860) || defined(CONFIG_RPXCLASSIC)
+ udelay (100000); /* wait 100 ms */
+#endif
+
+ return 1;
+}
+
+
+static void scc_halt (struct eth_device *dev)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl &=
+ ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ immr->im_ioport.iop_pcso &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+}
+
+#if 0
+void restart (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |=
+ (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+}
+#endif
+#endif
diff --git a/arch/powerpc/cpu/mpc8xx/serial.c b/arch/powerpc/cpu/mpc8xx/serial.c
new file mode 100644
index 0000000..664db65
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/serial.c
@@ -0,0 +1,745 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <commproc.h>
+#include <command.h>
+#include <serial.h>
+#include <watchdog.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if !defined(CONFIG_8xx_CONS_NONE) /* No Console at all */
+
+#if defined(CONFIG_8xx_CONS_SMC1) /* Console on SMC1 */
+#define SMC_INDEX 0
+#define PROFF_SMC PROFF_SMC1
+#define CPM_CR_CH_SMC CPM_CR_CH_SMC1
+
+#elif defined(CONFIG_8xx_CONS_SMC2) /* Console on SMC2 */
+#define SMC_INDEX 1
+#define PROFF_SMC PROFF_SMC2
+#define CPM_CR_CH_SMC CPM_CR_CH_SMC2
+
+#endif /* CONFIG_8xx_CONS_SMCx */
+
+#if defined(CONFIG_8xx_CONS_SCC1) /* Console on SCC1 */
+#define SCC_INDEX 0
+#define PROFF_SCC PROFF_SCC1
+#define CPM_CR_CH_SCC CPM_CR_CH_SCC1
+
+#elif defined(CONFIG_8xx_CONS_SCC2) /* Console on SCC2 */
+#define SCC_INDEX 1
+#define PROFF_SCC PROFF_SCC2
+#define CPM_CR_CH_SCC CPM_CR_CH_SCC2
+
+#elif defined(CONFIG_8xx_CONS_SCC3) /* Console on SCC3 */
+#define SCC_INDEX 2
+#define PROFF_SCC PROFF_SCC3
+#define CPM_CR_CH_SCC CPM_CR_CH_SCC3
+
+#elif defined(CONFIG_8xx_CONS_SCC4) /* Console on SCC4 */
+#define SCC_INDEX 3
+#define PROFF_SCC PROFF_SCC4
+#define CPM_CR_CH_SCC CPM_CR_CH_SCC4
+
+#endif /* CONFIG_8xx_CONS_SCCx */
+
+#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;
+
+static void serial_setdivisor(volatile cpm8xx_t *cp)
+{
+ int divisor=(gd->cpu_clk + 8*gd->baudrate)/16/gd->baudrate;
+
+ if(divisor/16>0x1000) {
+ /* bad divisor, assume 50MHz clock and 9600 baud */
+ divisor=(50*1000*1000 + 8*9600)/16/9600;
+ }
+
+#ifdef CONFIG_SYS_BRGCLK_PRESCALE
+ divisor /= CONFIG_SYS_BRGCLK_PRESCALE;
+#endif
+
+ if(divisor<=0x1000) {
+ cp->cp_brgc1=((divisor-1)<<1) | CPM_BRG_EN;
+ } else {
+ cp->cp_brgc1=((divisor/16-1)<<1) | CPM_BRG_EN | CPM_BRG_DIV16;
+ }
+}
+
+#if (defined (CONFIG_8xx_CONS_SMC1) || defined (CONFIG_8xx_CONS_SMC2))
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+static void smc_setbrg (void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = &(im->im_cpm);
+
+ /* Set up the baud rate generator.
+ * See 8xx_io/commproc.c for details.
+ *
+ * Wire BRG1 to SMCx
+ */
+
+ cp->cp_simode = 0x00000000;
+
+ serial_setdivisor(cp);
+}
+
+static int smc_init (void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile smc_t *sp;
+ volatile smc_uart_t *up;
+ volatile cpm8xx_t *cp = &(im->im_cpm);
+#if (!defined(CONFIG_8xx_CONS_SMC1)) && (defined(CONFIG_MPC823) || defined(CONFIG_MPC850))
+ volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);
+#endif
+ uint dpaddr;
+ volatile serialbuffer_t *rtx;
+
+ /* initialize pointers to SMC */
+
+ sp = (smc_t *) &(cp->cp_smc[SMC_INDEX]);
+ up = (smc_uart_t *) &cp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ up = (smc_uart_t *) &cp->cp_dpmem[up->smc_rpbase];
+#else
+ /* Disable relocation */
+ up->smc_rpbase = 0;
+#endif
+
+ /* Disable transmitter/receiver. */
+ sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+ /* Enable SDMA. */
+ im->im_siu_conf.sc_sdcr = 1;
+
+ /* clear error conditions */
+#ifdef CONFIG_SYS_SDSR
+ im->im_sdma.sdma_sdsr = CONFIG_SYS_SDSR;
+#else
+ im->im_sdma.sdma_sdsr = 0x83;
+#endif
+
+ /* clear SDMA interrupt mask */
+#ifdef CONFIG_SYS_SDMR
+ im->im_sdma.sdma_sdmr = CONFIG_SYS_SDMR;
+#else
+ im->im_sdma.sdma_sdmr = 0x00;
+#endif
+
+#if defined(CONFIG_8xx_CONS_SMC1)
+ /* Use Port B for SMC1 instead of other functions. */
+ cp->cp_pbpar |= 0x000000c0;
+ cp->cp_pbdir &= ~0x000000c0;
+ cp->cp_pbodr &= ~0x000000c0;
+#else /* CONFIG_8xx_CONS_SMC2 */
+# if defined(CONFIG_MPC823) || defined(CONFIG_MPC850)
+ /* Use Port A for SMC2 instead of other functions. */
+ ip->iop_papar |= 0x00c0;
+ ip->iop_padir &= ~0x00c0;
+ ip->iop_paodr &= ~0x00c0;
+# else /* must be a 860 then */
+ /* Use Port B for SMC2 instead of other functions.
+ */
+ cp->cp_pbpar |= 0x00000c00;
+ cp->cp_pbdir &= ~0x00000c00;
+ cp->cp_pbodr &= ~0x00000c00;
+# endif
+#endif
+
+#if defined(CONFIG_FADS) || defined(CONFIG_ADS)
+ /* Enable RS232 */
+#if defined(CONFIG_8xx_CONS_SMC1)
+ *((uint *) BCSR1) &= ~BCSR1_RS232EN_1;
+#else
+ *((uint *) BCSR1) &= ~BCSR1_RS232EN_2;
+#endif
+#endif /* CONFIG_FADS */
+
+#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
+ /* Enable Monitor Port Transceiver */
+ *((uchar *) BCSR0) |= BCSR0_ENMONXCVR ;
+#endif /* CONFIG_RPXLITE */
+
+ /* Set the physical address of the host memory buffers in
+ * the buffer descriptors.
+ */
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ /* allocate
+ * size of struct serialbuffer with bd rx/tx, buffer rx/tx and rx index
+ */
+ dpaddr = dpram_alloc_align((sizeof(serialbuffer_t)), 8);
+#else
+ dpaddr = CPM_SERIAL_BASE ;
+#endif
+
+ rtx = (serialbuffer_t *)&cp->cp_dpmem[dpaddr];
+ /* Allocate space for two buffer descriptors in the DP ram.
+ * For now, this address seems OK, but it may have to
+ * change with newer versions of the firmware.
+ * damm: allocating space after the two buffers for rx/tx data
+ */
+
+ 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 = SMC_EB;
+ up->smc_tfcr = SMC_EB;
+#if defined (CONFIG_SYS_SMC_UCODE_PATCH)
+ up->smc_rbptr = up->smc_rbase;
+ up->smc_tbptr = up->smc_tbase;
+ up->smc_rstate = 0;
+ up->smc_tstate = 0;
+#endif
+
+#if defined(CONFIG_MBX)
+ board_serial_init();
+#endif /* CONFIG_MBX */
+
+ /* Set UART mode, 8 bit, no parity, one stop.
+ * Enable receive and transmit.
+ */
+ sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+
+ /* Mask all interrupts and remove anything pending.
+ */
+ sp->smc_smcm = 0;
+ sp->smc_smce = 0xff;
+
+#ifdef CONFIG_SYS_SPC1920_SMC1_CLK4
+ /* clock source is PLD */
+
+ /* set freq to 19200 Baud */
+ *((volatile uchar *) CONFIG_SYS_SPC1920_PLD_BASE+6) = 0x3;
+ /* configure clk4 as input */
+ im->im_ioport.iop_pdpar |= 0x800;
+ im->im_ioport.iop_pddir &= ~0x800;
+
+ cp->cp_simode = ((cp->cp_simode & ~0xf000) | 0x7000);
+#else
+ /* Set up the baud rate generator */
+ smc_setbrg ();
+#endif
+
+ /* 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_CH_SMC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ /* Enable transmitter/receiver. */
+ sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+ return (0);
+}
+
+static void
+smc_putc(const char c)
+{
+ volatile smc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+ volatile serialbuffer_t *rtx;
+
+#ifdef CONFIG_MODEM_SUPPORT
+ if (gd->be_quiet)
+ return;
+#endif
+
+ if (c == '\n')
+ smc_putc ('\r');
+
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
+#endif
+
+ rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+ /* Wait for last character to go. */
+ rtx->txbuf = c;
+ rtx->txbd.cbd_datlen = 1;
+ rtx->txbd.cbd_sc |= BD_SC_READY;
+ __asm__("eieio");
+
+ while (rtx->txbd.cbd_sc & BD_SC_READY) {
+ WATCHDOG_RESET ();
+ __asm__("eieio");
+ }
+}
+
+static void
+smc_puts (const char *s)
+{
+ while (*s) {
+ smc_putc (*s++);
+ }
+}
+
+static int
+smc_getc(void)
+{
+ volatile smc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+ volatile serialbuffer_t *rtx;
+ unsigned char c;
+
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
+#endif
+ rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+ /* Wait for character to show up. */
+ while (rtx->rxbd.cbd_sc & BD_SC_EMPTY)
+ WATCHDOG_RESET ();
+
+ /* 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
+smc_tstc(void)
+{
+ volatile smc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+ volatile serialbuffer_t *rtx;
+
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
+#endif
+
+ rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+ return !(rtx->rxbd.cbd_sc & BD_SC_EMPTY);
+}
+
+struct serial_device serial_smc_device =
+{
+ "serial_smc",
+ "SMC",
+ smc_init,
+ smc_setbrg,
+ smc_getc,
+ smc_tstc,
+ smc_putc,
+ smc_puts,
+};
+
+#endif /* CONFIG_8xx_CONS_SMC1 || CONFIG_8xx_CONS_SMC2 */
+
+#if defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) || \
+ defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4)
+
+static void
+scc_setbrg (void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = &(im->im_cpm);
+
+ /* Set up the baud rate generator.
+ * See 8xx_io/commproc.c for details.
+ *
+ * Wire BRG1 to SCCx
+ */
+
+ cp->cp_sicr &= ~(0x000000FF << (8 * SCC_INDEX));
+
+ serial_setdivisor(cp);
+}
+
+static int scc_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 cpm8xx_t *cp = &(im->im_cpm);
+ uint dpaddr;
+#if (SCC_INDEX != 2) || !defined(CONFIG_MPC850)
+ volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);
+#endif
+
+ /* initialize pointers to SCC */
+
+ sp = (scc_t *) &(cp->cp_scc[SCC_INDEX]);
+ up = (scc_uart_t *) &cp->cp_dparam[PROFF_SCC];
+
+#if defined(CONFIG_LWMON) && defined(CONFIG_8xx_CONS_SCC2)
+ { /* Disable Ethernet, enable Serial */
+ uchar c;
+
+ c = pic_read (0x61);
+ c &= ~0x40; /* enable COM3 */
+ c |= 0x80; /* disable Ethernet */
+ pic_write (0x61, c);
+
+ /* enable RTS2 */
+ cp->cp_pbpar |= 0x2000;
+ cp->cp_pbdat |= 0x2000;
+ cp->cp_pbdir |= 0x2000;
+ }
+#endif /* CONFIG_LWMON */
+
+ /* Disable transmitter/receiver. */
+ sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+#if (SCC_INDEX == 2) && defined(CONFIG_MPC850)
+ /*
+ * The MPC850 has SCC3 on Port B
+ */
+ cp->cp_pbpar |= 0x06;
+ cp->cp_pbdir &= ~0x06;
+ cp->cp_pbodr &= ~0x06;
+
+#elif (SCC_INDEX < 2) || !defined(CONFIG_IP860)
+ /*
+ * Standard configuration for SCC's is on Part A
+ */
+ ip->iop_papar |= ((3 << (2 * SCC_INDEX)));
+ ip->iop_padir &= ~((3 << (2 * SCC_INDEX)));
+ ip->iop_paodr &= ~((3 << (2 * SCC_INDEX)));
+#else
+ /*
+ * The IP860 has SCC3 and SCC4 on Port D
+ */
+ ip->iop_pdpar |= ((3 << (2 * SCC_INDEX)));
+#endif
+
+ /* Allocate space for two buffer descriptors in the DP ram. */
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ dpaddr = dpram_alloc_align (sizeof(cbd_t)*2 + 2, 8) ;
+#else
+ dpaddr = CPM_SERIAL2_BASE ;
+#endif
+
+ /* Enable SDMA. */
+ im->im_siu_conf.sc_sdcr = 0x0001;
+
+ /* Set the physical address of the host memory buffers in
+ * the buffer descriptors.
+ */
+
+ rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
+ rbdf->cbd_bufaddr = (uint) (rbdf+2);
+ rbdf->cbd_sc = 0;
+ tbdf = rbdf + 1;
+ tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+ tbdf->cbd_sc = 0;
+
+ /* Set up the baud rate generator. */
+ scc_setbrg ();
+
+ /* Set up the uart parameters in the parameter ram. */
+ up->scc_genscc.scc_rbase = dpaddr;
+ up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+
+ /* Initialize Tx/Rx parameters. */
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ up->scc_genscc.scc_rfcr = SCC_EB | 0x05;
+ up->scc_genscc.scc_tfcr = SCC_EB | 0x05;
+
+ up->scc_genscc.scc_mrblr = 1; /* Single character receive */
+ up->scc_maxidl = 0; /* disable max idle */
+ up->scc_brkcr = 1; /* send one break character on stop TX */
+ up->scc_parec = 0;
+ up->scc_frmec = 0;
+ up->scc_nosec = 0;
+ up->scc_brkec = 0;
+ up->scc_uaddr1 = 0;
+ up->scc_uaddr2 = 0;
+ up->scc_toseq = 0;
+ up->scc_char1 = 0x8000;
+ up->scc_char2 = 0x8000;
+ up->scc_char3 = 0x8000;
+ up->scc_char4 = 0x8000;
+ up->scc_char5 = 0x8000;
+ up->scc_char6 = 0x8000;
+ up->scc_char7 = 0x8000;
+ up->scc_char8 = 0x8000;
+ up->scc_rccm = 0xc0ff;
+
+ /* Set low latency / small fifo. */
+ sp->scc_gsmrh = SCC_GSMRH_RFW;
+
+ /* Set SCC(x) clock mode to 16x
+ * See 8xx_io/commproc.c for details.
+ *
+ * Wire BRG1 to SCCn
+ */
+
+ /* Set UART mode, clock divider 16 on Tx and Rx */
+ sp->scc_gsmrl &= ~0xF;
+ sp->scc_gsmrl |=
+ (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+ sp->scc_psmr = 0;
+ sp->scc_psmr |= SCU_PSMR_CL;
+
+ /* Mask all interrupts and remove anything pending. */
+ sp->scc_sccm = 0;
+ sp->scc_scce = 0xffff;
+ sp->scc_dsr = 0x7e7e;
+ sp->scc_psmr = 0x3000;
+
+ /* Make the first buffer the only buffer. */
+ tbdf->cbd_sc |= BD_SC_WRAP;
+ rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+ /* Enable transmitter/receiver. */
+ sp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ return (0);
+}
+
+static void
+scc_putc(const char c)
+{
+ volatile cbd_t *tbdf;
+ volatile char *buf;
+ volatile scc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+
+#ifdef CONFIG_MODEM_SUPPORT
+ if (gd->be_quiet)
+ return;
+#endif
+
+ if (c == '\n')
+ scc_putc ('\r');
+
+ up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+ tbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_tbase];
+
+ /* Wait for last character to go. */
+
+ buf = (char *)tbdf->cbd_bufaddr;
+
+ *buf = c;
+ tbdf->cbd_datlen = 1;
+ tbdf->cbd_sc |= BD_SC_READY;
+ __asm__("eieio");
+
+ while (tbdf->cbd_sc & BD_SC_READY) {
+ __asm__("eieio");
+ WATCHDOG_RESET ();
+ }
+}
+
+static void
+scc_puts (const char *s)
+{
+ while (*s) {
+ scc_putc (*s++);
+ }
+}
+
+static int
+scc_getc(void)
+{
+ volatile cbd_t *rbdf;
+ volatile unsigned char *buf;
+ volatile scc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+ unsigned char c;
+
+ up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+ rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase];
+
+ /* Wait for character to show up. */
+ buf = (unsigned char *)rbdf->cbd_bufaddr;
+
+ while (rbdf->cbd_sc & BD_SC_EMPTY)
+ WATCHDOG_RESET ();
+
+ c = *buf;
+ rbdf->cbd_sc |= BD_SC_EMPTY;
+
+ return(c);
+}
+
+static int
+scc_tstc(void)
+{
+ volatile cbd_t *rbdf;
+ volatile scc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+
+ up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+ rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase];
+
+ return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
+
+struct serial_device serial_scc_device =
+{
+ "serial_scc",
+ "SCC",
+ scc_init,
+ scc_setbrg,
+ scc_getc,
+ scc_tstc,
+ scc_putc,
+ scc_puts,
+};
+
+#endif /* CONFIG_8xx_CONS_SCCx */
+
+#ifdef CONFIG_MODEM_SUPPORT
+void disable_putc(void)
+{
+ gd->be_quiet = 1;
+}
+
+void enable_putc(void)
+{
+ gd->be_quiet = 0;
+}
+#endif
+
+#if defined(CONFIG_CMD_KGDB)
+
+void
+kgdb_serial_init(void)
+{
+ int i = -1;
+
+ if (strcmp(default_serial_console()->ctlr, "SMC") == 0)
+ {
+#if defined(CONFIG_8xx_CONS_SMC1)
+ i = 1;
+#elif defined(CONFIG_8xx_CONS_SMC2)
+ i = 2;
+#endif
+ }
+ else if (strcmp(default_serial_console()->ctlr, "SMC") == 0)
+ {
+#if defined(CONFIG_8xx_CONS_SCC1)
+ i = 1;
+#elif defined(CONFIG_8xx_CONS_SCC2)
+ i = 2;
+#elif defined(CONFIG_8xx_CONS_SCC3)
+ i = 3;
+#elif defined(CONFIG_8xx_CONS_SCC4)
+ i = 4;
+#endif
+ }
+
+ if (i >= 0)
+ {
+ serial_printf("[on %s%d] ", default_serial_console()->ctlr, i);
+ }
+}
+
+void
+putDebugChar (int c)
+{
+ serial_putc (c);
+}
+
+void
+putDebugStr (const char *str)
+{
+ serial_puts (str);
+}
+
+int
+getDebugChar (void)
+{
+ return serial_getc();
+}
+
+void
+kgdb_interruptible (int yes)
+{
+ return;
+}
+#endif
+
+#endif /* CONFIG_8xx_CONS_NONE */
diff --git a/arch/powerpc/cpu/mpc8xx/speed.c b/arch/powerpc/cpu/mpc8xx/speed.c
new file mode 100644
index 0000000..f309f29
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/speed.c
@@ -0,0 +1,416 @@
+/*
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if !defined(CONFIG_8xx_CPUCLK_DEFAULT) || defined(CONFIG_SYS_MEASURE_CPUCLK) || defined(DEBUG)
+
+#define PITC_SHIFT 16
+#define PITR_SHIFT 16
+/* pitc values to time for 58/8192 seconds (about 70.8 milliseconds) */
+#define SPEED_PIT_COUNTS 58
+#define SPEED_PITC ((SPEED_PIT_COUNTS - 1) << PITC_SHIFT)
+#define SPEED_PITC_INIT ((SPEED_PIT_COUNTS + 1) << PITC_SHIFT)
+
+/* Access functions for the Machine State Register */
+static __inline__ unsigned long get_msr(void)
+{
+ unsigned long msr;
+
+ asm volatile("mfmsr %0" : "=r" (msr) :);
+ return msr;
+}
+
+static __inline__ void set_msr(unsigned long msr)
+{
+ asm volatile("mtmsr %0" : : "r" (msr));
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Measure CPU clock speed (core clock GCLK1, GCLK2),
+ * also determine bus clock speed (checking bus divider factor)
+ *
+ * (Approx. GCLK frequency in Hz)
+ *
+ * Initializes timer 2 and PIT, but disables them before return.
+ * [Use timer 2, because MPC823 CPUs mask 0.x do not have timers 3 and 4]
+ *
+ * When measuring the CPU clock against the PIT, we count cpu clocks
+ * for 58/8192 seconds with a prescale divide by 177 for the cpu clock.
+ * These strange values for the timing interval and prescaling are used
+ * because the formula for the CPU clock is:
+ *
+ * CPU clock = count * (177 * (8192 / 58))
+ *
+ * = count * 24999.7241
+ *
+ * which is very close to
+ *
+ * = count * 25000
+ *
+ * Since the count gives the CPU clock divided by 25000, we can get
+ * the CPU clock rounded to the nearest 0.1 MHz by
+ *
+ * CPU clock = ((count + 2) / 4) * 100000;
+ *
+ * The rounding is important since the measurement is sometimes going
+ * to be high or low by 0.025 MHz, depending on exactly how the clocks
+ * and counters interact. By rounding we get the exact answer for any
+ * CPU clock that is an even multiple of 0.1 MHz.
+ */
+
+unsigned long measure_gclk(void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile cpmtimer8xx_t *timerp = &immr->im_cpmtimer;
+ ulong timer2_val;
+ ulong msr_val;
+
+#ifdef CONFIG_SYS_8XX_XIN
+ /* dont use OSCM, only use EXTCLK/512 */
+ immr->im_clkrst.car_sccr |= SCCR_RTSEL | SCCR_RTDIV;
+#else
+ immr->im_clkrst.car_sccr &= ~(SCCR_RTSEL | SCCR_RTDIV);
+#endif
+
+ /* Reset + Stop Timer 2, no cascading
+ */
+ timerp->cpmt_tgcr &= ~(TGCR_CAS2 | TGCR_RST2);
+
+ /* Keep stopped, halt in debug mode
+ */
+ timerp->cpmt_tgcr |= (TGCR_FRZ2 | TGCR_STP2);
+
+ /* Timer 2 setup:
+ * Output ref. interrupt disable, int. clock
+ * Prescale by 177. Note that prescaler divides by value + 1
+ * so we must subtract 1 here.
+ */
+ timerp->cpmt_tmr2 = ((177 - 1) << TMR_PS_SHIFT) | TMR_ICLK_IN_GEN;
+
+ timerp->cpmt_tcn2 = 0; /* reset state */
+ timerp->cpmt_tgcr |= TGCR_RST2; /* enable timer 2 */
+
+ /*
+ * PIT setup:
+ *
+ * We want to time for SPEED_PITC_COUNTS counts (of 8192 Hz),
+ * so the count value would be SPEED_PITC_COUNTS - 1.
+ * But there would be an uncertainty in the start time of 1/4
+ * count since when we enable the PIT the count is not
+ * synchronized to the 32768 Hz oscillator. The trick here is
+ * to start the count higher and wait until the PIT count
+ * changes to the required value before starting timer 2.
+ *
+ * One count high should be enough, but occasionally the start
+ * is off by 1 or 2 counts of 32768 Hz. With the start value
+ * set two counts high it seems very reliable.
+ */
+
+ immr->im_sitk.sitk_pitck = KAPWR_KEY; /* PIT initialization */
+ immr->im_sit.sit_pitc = SPEED_PITC_INIT;
+
+ immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+ immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
+
+ /*
+ * Start measurement - disable interrupts, just in case
+ */
+ msr_val = get_msr ();
+ set_msr (msr_val & ~MSR_EE);
+
+ immr->im_sit.sit_piscr |= PISCR_PTE;
+
+ /* spin until get exact count when we want to start */
+ while (immr->im_sit.sit_pitr > SPEED_PITC);
+
+ timerp->cpmt_tgcr &= ~TGCR_STP2; /* Start Timer 2 */
+ while ((immr->im_sit.sit_piscr & PISCR_PS) == 0);
+ timerp->cpmt_tgcr |= TGCR_STP2; /* Stop Timer 2 */
+
+ /* re-enable external interrupts if they were on */
+ set_msr (msr_val);
+
+ /* Disable timer and PIT
+ */
+ timer2_val = timerp->cpmt_tcn2; /* save before reset timer */
+
+ timerp->cpmt_tgcr &= ~(TGCR_RST2 | TGCR_FRZ2 | TGCR_STP2);
+ immr->im_sit.sit_piscr &= ~PISCR_PTE;
+
+#if defined(CONFIG_SYS_8XX_XIN)
+ /* not using OSCM, using XIN, so scale appropriately */
+ return (((timer2_val + 2) / 4) * (CONFIG_SYS_8XX_XIN/512))/8192 * 100000L;
+#else
+ return ((timer2_val + 2) / 4) * 100000L; /* convert to Hz */
+#endif
+}
+
+#endif
+
+void get_brgclk(uint sccr)
+{
+ uint divider = 0;
+
+ switch((sccr&SCCR_DFBRG11)>>11){
+ case 0:
+ divider = 1;
+ break;
+ case 1:
+ divider = 4;
+ break;
+ case 2:
+ divider = 16;
+ break;
+ case 3:
+ divider = 64;
+ break;
+ }
+ gd->brg_clk = gd->cpu_clk/divider;
+}
+
+#if !defined(CONFIG_8xx_CPUCLK_DEFAULT)
+
+/*
+ * get_clocks() fills in gd->cpu_clock depending on CONFIG_8xx_GCLK_FREQ
+ * or (if it is not defined) measure_gclk() (which uses the ref clock)
+ * from above.
+ */
+int get_clocks (void)
+{
+ uint immr = get_immr (0); /* Return full IMMR contents */
+ volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+ uint sccr = immap->im_clkrst.car_sccr;
+ /*
+ * If for some reason measuring the gclk frequency won't
+ * work, we return the hardwired value.
+ * (For example, the cogent CMA286-60 CPU module has no
+ * separate oscillator for PITRTCLK)
+ */
+#if defined(CONFIG_8xx_GCLK_FREQ)
+ gd->cpu_clk = CONFIG_8xx_GCLK_FREQ;
+#elif defined(CONFIG_8xx_OSCLK)
+#define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT)
+ uint pll = immap->im_clkrst.car_plprcr;
+ uint clk;
+
+ if ((immr & 0x0FFF) >= MPC8xx_NEW_CLK) { /* MPC866/87x/88x series */
+ clk = ((CONFIG_8xx_OSCLK / (PLPRCR_val(PDF)+1)) *
+ (PLPRCR_val(MFI) + PLPRCR_val(MFN) / (PLPRCR_val(MFD)+1))) /
+ (1<<PLPRCR_val(S));
+ } else {
+ clk = CONFIG_8xx_OSCLK * (PLPRCR_val(MF)+1);
+ }
+ if (pll & PLPRCR_CSRC) { /* Low frequency division factor is used */
+ gd->cpu_clk = clk / (2 << ((sccr >> 8) & 7));
+ } else { /* High frequency division factor is used */
+ gd->cpu_clk = clk / (1 << ((sccr >> 5) & 7));
+ }
+#else
+ gd->cpu_clk = measure_gclk();
+#endif /* CONFIG_8xx_GCLK_FREQ */
+
+ if ((sccr & SCCR_EBDF11) == 0) {
+ /* No Bus Divider active */
+ gd->bus_clk = gd->cpu_clk;
+ } else {
+ /* The MPC8xx has only one BDF: half clock speed */
+ gd->bus_clk = gd->cpu_clk / 2;
+ }
+
+ get_brgclk(sccr);
+
+ return (0);
+}
+
+#else /* CONFIG_8xx_CPUCLK_DEFAULT defined, use dynamic clock setting */
+
+static long init_pll_866 (long clk);
+
+/* This function sets up PLL (init_pll_866() is called) and
+ * fills gd->cpu_clk and gd->bus_clk according to the environment
+ * variable 'cpuclk' or to CONFIG_8xx_CPUCLK_DEFAULT (if 'cpuclk'
+ * contains invalid value).
+ * This functions requires an MPC866 or newer series CPU.
+ */
+int get_clocks_866 (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ char tmp[64];
+ long cpuclk = 0;
+ long sccr_reg;
+
+ if (getenv_r ("cpuclk", tmp, sizeof (tmp)) > 0)
+ cpuclk = simple_strtoul (tmp, NULL, 10) * 1000000;
+
+ if ((CONFIG_SYS_8xx_CPUCLK_MIN > cpuclk) || (CONFIG_SYS_8xx_CPUCLK_MAX < cpuclk))
+ cpuclk = CONFIG_8xx_CPUCLK_DEFAULT;
+
+ gd->cpu_clk = init_pll_866 (cpuclk);
+#if defined(CONFIG_SYS_MEASURE_CPUCLK)
+ gd->cpu_clk = measure_gclk ();
+#endif
+
+ get_brgclk(immr->im_clkrst.car_sccr);
+
+ /* if cpu clock <= 66 MHz then set bus division factor to 1,
+ * otherwise set it to 2
+ */
+ sccr_reg = immr->im_clkrst.car_sccr;
+ sccr_reg &= ~SCCR_EBDF11;
+
+ if (gd->cpu_clk <= 66000000) {
+ sccr_reg |= SCCR_EBDF00; /* bus division factor = 1 */
+ gd->bus_clk = gd->cpu_clk;
+ } else {
+ sccr_reg |= SCCR_EBDF01; /* bus division factor = 2 */
+ gd->bus_clk = gd->cpu_clk / 2;
+ }
+ immr->im_clkrst.car_sccr = sccr_reg;
+
+ return (0);
+}
+
+/* Adjust sdram refresh rate to actual CPU clock.
+ */
+int sdram_adjust_866 (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ long mamr;
+
+ mamr = immr->im_memctl.memc_mamr;
+ mamr &= ~MAMR_PTA_MSK;
+ mamr |= ((gd->cpu_clk / CONFIG_SYS_PTA_PER_CLK) << MAMR_PTA_SHIFT);
+ immr->im_memctl.memc_mamr = mamr;
+
+ return (0);
+}
+
+/* Configure PLL for MPC866/859/885 CPU series
+ * PLL multiplication factor is set to the value nearest to the desired clk,
+ * assuming a oscclk of 10 MHz.
+ */
+static long init_pll_866 (long clk)
+{
+ extern void plprcr_write_866 (long);
+
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ long n, plprcr;
+ char mfi, mfn, mfd, s, pdf;
+ long step_mfi, step_mfn;
+
+ if (clk < 20000000) {
+ clk *= 2;
+ pdf = 1;
+ } else {
+ pdf = 0;
+ }
+
+ if (clk < 40000000) {
+ s = 2;
+ step_mfi = CONFIG_8xx_OSCLK / 4;
+ mfd = 7;
+ step_mfn = CONFIG_8xx_OSCLK / 30;
+ } else if (clk < 80000000) {
+ s = 1;
+ step_mfi = CONFIG_8xx_OSCLK / 2;
+ mfd = 14;
+ step_mfn = CONFIG_8xx_OSCLK / 30;
+ } else {
+ s = 0;
+ step_mfi = CONFIG_8xx_OSCLK;
+ mfd = 29;
+ step_mfn = CONFIG_8xx_OSCLK / 30;
+ }
+
+ /* Calculate integer part of multiplication factor
+ */
+ n = clk / step_mfi;
+ mfi = (char)n;
+
+ /* Calculate numerator of fractional part of multiplication factor
+ */
+ n = clk - (n * step_mfi);
+ mfn = (char)(n / step_mfn);
+
+ /* Calculate effective clk
+ */
+ n = ((mfi * step_mfi) + (mfn * step_mfn)) / (pdf + 1);
+
+ immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+
+ plprcr = (immr->im_clkrst.car_plprcr & ~(PLPRCR_MFN_MSK
+ | PLPRCR_MFD_MSK | PLPRCR_S_MSK
+ | PLPRCR_MFI_MSK | PLPRCR_DBRMO
+ | PLPRCR_PDF_MSK))
+ | (mfn << PLPRCR_MFN_SHIFT)
+ | (mfd << PLPRCR_MFD_SHIFT)
+ | (s << PLPRCR_S_SHIFT)
+ | (mfi << PLPRCR_MFI_SHIFT)
+ | (pdf << PLPRCR_PDF_SHIFT);
+
+ if( (mfn > 0) && ((mfd / mfn) > 10) )
+ plprcr |= PLPRCR_DBRMO;
+
+ plprcr_write_866 (plprcr); /* set value using SIU4/9 workaround */
+ immr->im_clkrstk.cark_plprcrk = 0x00000000;
+
+ return (n);
+}
+
+#endif /* CONFIG_8xx_CPUCLK_DEFAULT */
+
+#if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) \
+ && !defined(CONFIG_TQM885D)
+/*
+ * Adjust sdram refresh rate to actual CPU clock
+ * and set timebase source according to actual CPU clock
+ */
+int adjust_sdram_tbs_8xx (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ long mamr;
+ long sccr;
+
+ mamr = immr->im_memctl.memc_mamr;
+ mamr &= ~MAMR_PTA_MSK;
+ mamr |= ((gd->cpu_clk / CONFIG_SYS_PTA_PER_CLK) << MAMR_PTA_SHIFT);
+ immr->im_memctl.memc_mamr = mamr;
+
+ if (gd->cpu_clk < 67000000) {
+ sccr = immr->im_clkrst.car_sccr;
+ sccr |= SCCR_TBS;
+ immr->im_clkrst.car_sccr = sccr;
+ }
+
+ return (0);
+}
+#endif /* CONFIG_TQM8xxL/M, !TQM866M, !TQM885D */
+
+/* ------------------------------------------------------------------------- */
diff --git a/arch/powerpc/cpu/mpc8xx/spi.c b/arch/powerpc/cpu/mpc8xx/spi.c
new file mode 100644
index 0000000..b2ac23e
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/spi.c
@@ -0,0 +1,560 @@
+/*
+ * 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 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * MPC8xx 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 <mpc8xx.h>
+#include <commproc.h>
+#include <linux/ctype.h>
+#include <malloc.h>
+#include <post.h>
+#include <serial.h>
+
+#if (defined(CONFIG_SPI)) || (CONFIG_POST & CONFIG_SYS_POST_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 0xb00 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 0xB00
+#endif
+
+#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 *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
+ [CONFIG_SYS_SPI_INIT_OFFSET];
+static uchar *txbuf =
+ (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
+ [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 cpic8xx_t *cpi;
+ volatile cpm8xx_t *cp;
+ volatile iop8xx_t *iop;
+ volatile cbd_t *tbdf, *rbdf;
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ cpi = (cpic8xx_t *)&immr->im_cpic;
+ iop = (iop8xx_t *) &immr->im_ioport;
+ cp = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CONFIG_SYS_SPI_UCODE_PATCH
+ spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
+#else
+ spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+ /* Disable relocation */
+ spi->spi_rpbase = 0;
+#endif
+
+/* 1 */
+ /* ------------------------------------------------
+ * Initialize Port B SPI pins -> page 34-8 MPC860UM
+ * (we are only in Master Mode !)
+ * ------------------------------------------------ */
+
+ /* --------------------------------------------
+ * GPIO or per. Function
+ * PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO)
+ * PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI)
+ * PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK)
+ * PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for PCUE/CCM-EEPROM)
+ * -------------------------------------------- */
+ cp->cp_pbpar |= 0x0000000E; /* set bits */
+ cp->cp_pbpar &= ~0x00000001; /* reset bit */
+
+ /* ----------------------------------------------
+ * In/Out or per. Function 0/1
+ * PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO
+ * PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI
+ * PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK
+ * PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for PCUE/CCM-EEPROM
+ * ---------------------------------------------- */
+ cp->cp_pbdir |= 0x0000000F;
+
+ /* ----------------------------------------------
+ * open drain or active output
+ * PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO
+ * PBODR[29] = 0 [0x00000004] -> active output SPIMOSI
+ * PBODR[30] = 0 [0x00000002] -> active output: SPICLK
+ * PBODR[31] = 0 [0x00000001] -> active output: GPIO OUT: CS for PCUE/CCM
+ * ---------------------------------------------- */
+
+ cp->cp_pbodr |= 0x00000008;
+ cp->cp_pbodr &= ~0x00000007;
+
+ /* 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 = dpram_alloc_align (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 */
+#ifdef CONFIG_SYS_SPI_UCODE_PATCH
+ /*
+ * Initialize required parameters if using microcode patch.
+ */
+ spi->spi_rstate = 0;
+ spi->spi_tstate = 0;
+#else
+ /* Init SPI Tx + Rx Parameters */
+ while (cp->cp_cpcr & CPM_CR_FLG)
+ ;
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG)
+ ;
+#endif /* CONFIG_SYS_SPI_UCODE_PATCH */
+
+/* 5 */
+ /* Set SDMA configuration register */
+ immr->im_siu_conf.sc_sdcr = 0x0001;
+
+/* 6 */
+ /* Set to big endian. */
+ spi->spi_tfcr = SMC_EB;
+ spi->spi_rfcr = SMC_EB;
+
+/* 7 */
+ /* Set maximum receive size. */
+ spi->spi_mrblr = MAX_BUFFER;
+
+/* 8 + 9 */
+ /* tx and rx buffer descriptors */
+ tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+ rbdf = (cbd_t *) & cp->cp_dpmem[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 */
+ cp->cp_spim = 0; /* Mask all SPI events */
+ cp->cp_spie = SPI_EMASK; /* Clear 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 cpm8xx_t *cp;
+ volatile spi_t *spi;
+ volatile immap_t *immr;
+ volatile cbd_t *tbdf, *rbdf;
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ cp = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CONFIG_SYS_SPI_UCODE_PATCH
+ spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
+#else
+ spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+ /* Disable relocation */
+ spi->spi_rpbase = 0;
+#endif
+
+ /* tx and rx buffer descriptors */
+ tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+ rbdf = (cbd_t *) & cp->cp_dpmem[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 cpm8xx_t *cp;
+ volatile spi_t *spi;
+ cbd_t *tbdf, *rbdf;
+ ushort loop;
+ int tm;
+
+ DPRINT (("*** spi_xfer entered ***\n"));
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ cp = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CONFIG_SYS_SPI_UCODE_PATCH
+ spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
+#else
+ spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+ /* Disable relocation */
+ spi->spi_rpbase = 0;
+#endif
+
+ tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+ rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
+
+ /* Set CS for device */
+ cp->cp_pbdat &= ~0x0001;
+
+ /* 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 */
+
+ loop = cp->cp_spmode & SPMODE_LOOP;
+ cp->cp_spmode = /*SPMODE_DIV16 |*/ /* BRG/16 mode not used here */
+ loop |
+ SPMODE_REV |
+ SPMODE_MSTR |
+ SPMODE_EN |
+ SPMODE_LEN(8) | /* 8 Bits per char */
+ SPMODE_PM(0x8) ; /* medium speed */
+ cp->cp_spim = 0; /* Mask all SPI events */
+ cp->cp_spie = SPI_EMASK; /* Clear all SPI events */
+
+ /* start spi transfer */
+ DPRINT (("*** spi_xfer: Performing transfer ...\n"));
+ cp->cp_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 (cp->cp_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 */
+ cp->cp_pbdat |= 0x0001;
+
+ return count;
+}
+#endif /* CONFIG_SPI || (CONFIG_POST & CONFIG_SYS_POST_SPI) */
+
+/*
+ * SPI test
+ *
+ * The Serial Peripheral Interface (SPI) is tested in the local loopback mode.
+ * The interface is configured accordingly and several packets
+ * are transfered. The configurable test parameters are:
+ * TEST_MIN_LENGTH - minimum size of packet to transfer
+ * TEST_MAX_LENGTH - maximum size of packet to transfer
+ * TEST_NUM - number of tests
+ */
+
+#if CONFIG_POST & CONFIG_SYS_POST_SPI
+
+#define TEST_MIN_LENGTH 1
+#define TEST_MAX_LENGTH MAX_BUFFER
+#define TEST_NUM 1
+
+static void packet_fill (char * packet, int length)
+{
+ char c = (char) length;
+ int i;
+
+ for (i = 0; i < length; i++)
+ {
+ packet[i] = c++;
+ }
+}
+
+static int packet_check (char * packet, int length)
+{
+ char c = (char) length;
+ int i;
+
+ for (i = 0; i < length; i++) {
+ if (packet[i] != c++) return -1;
+ }
+
+ return 0;
+}
+
+int spi_post_test (int flags)
+{
+ int res = -1;
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = (cpm8xx_t *) & immr->im_cpm;
+ int i;
+ int l;
+
+ spi_init_f ();
+ spi_init_r ();
+
+ cp->cp_spmode |= SPMODE_LOOP;
+
+ for (i = 0; i < TEST_NUM; i++) {
+ for (l = TEST_MIN_LENGTH; l <= TEST_MAX_LENGTH; l += 8) {
+ packet_fill ((char *)txbuf, l);
+
+ spi_xfer (l);
+
+ if (packet_check ((char *)rxbuf, l) < 0) {
+ goto Done;
+ }
+ }
+ }
+
+ res = 0;
+
+ Done:
+
+ cp->cp_spmode &= ~SPMODE_LOOP;
+
+ /*
+ * SCC2 parameter RAM space overlaps
+ * the SPI parameter RAM space. So we need to restore
+ * the SCC2 configuration if it is used by UART.
+ */
+
+#if !defined(CONFIG_8xx_CONS_NONE)
+ serial_reinit_all ();
+#endif
+
+ if (res != 0) {
+ post_log ("SPI test failed\n");
+ }
+
+ return res;
+}
+#endif /* CONFIG_POST & CONFIG_SYS_POST_SPI */
diff --git a/arch/powerpc/cpu/mpc8xx/start.S b/arch/powerpc/cpu/mpc8xx/start.S
new file mode 100644
index 0000000..7cf602f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/start.S
@@ -0,0 +1,684 @@
+/*
+ * 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>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* U-Boot - Startup Code for PowerPC based Embedded Boards
+ *
+ *
+ * The processor starts at 0x00000100 and the code is executed
+ * from flash. The code is organized to be at an other address
+ * in memory, but as long we don't jump around before relocating,
+ * board_init lies at a quite high address and when the cpu has
+ * jumped there, everything is ok.
+ * This works because the cpu gives the FLASH (CS0) the whole
+ * address space at startup, and board_init lies as a echo of
+ * the flash somewhere up there in the memory map.
+ *
+ * board_init will change CS0 to be positioned at the correct
+ * address and (s)dram will be positioned at address 0
+ */
+#include <config.h>
+#include <mpc8xx.h>
+#include <timestamp.h>
+#include <version.h>
+
+#define CONFIG_8xx 1 /* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef CONFIG_IDENT_STRING
+#define CONFIG_IDENT_STRING ""
+#endif
+
+/* We don't want the MMU yet.
+*/
+#undef MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME | MSR_RI ) /* Machine Check and Recoverable Interr. */
+
+/*
+ * 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(_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+ .text
+ .long 0x27051956 /* U-Boot Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION
+ .ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+ .ascii CONFIG_IDENT_STRING, "\0"
+
+ . = EXC_OFF_SYS_RESET
+ .globl _start
+_start:
+ lis r3, CONFIG_SYS_IMMR@h /* position IMMR */
+ mtspr 638, r3
+ li r21, BOOTFLAG_COLD /* Normal Power-On: Boot from FLASH */
+ b boot_cold
+
+ . = EXC_OFF_SYS_RESET + 0x10
+
+ .globl _start_warm
+_start_warm:
+ li r21, BOOTFLAG_WARM /* Software reboot */
+ b boot_warm
+
+boot_cold:
+boot_warm:
+
+ /* Initialize machine status; enable machine check interrupt */
+ /*----------------------------------------------------------------------*/
+ li r3, MSR_KERNEL /* Set ME, RI flags */
+ mtmsr r3
+ mtspr SRR1, r3 /* Make SRR1 match MSR */
+
+ mfspr r3, ICR /* clear Interrupt Cause Register */
+
+ /* Initialize debug port registers */
+ /*----------------------------------------------------------------------*/
+ xor r0, r0, r0 /* Clear R0 */
+ mtspr LCTRL1, r0 /* Initialize debug port regs */
+ mtspr LCTRL2, r0
+ mtspr COUNTA, r0
+ mtspr COUNTB, r0
+
+ /* Reset the caches */
+ /*----------------------------------------------------------------------*/
+
+ mfspr r3, IC_CST /* Clear error bits */
+ mfspr r3, DC_CST
+
+ lis r3, IDC_UNALL@h /* Unlock all */
+ mtspr IC_CST, r3
+ mtspr DC_CST, r3
+
+ lis r3, IDC_INVALL@h /* Invalidate all */
+ mtspr IC_CST, r3
+ mtspr DC_CST, r3
+
+ lis r3, IDC_DISABLE@h /* Disable data cache */
+ mtspr DC_CST, r3
+
+#if !defined(CONFIG_SYS_DELAYED_ICACHE)
+ /* On IP860 and PCU E,
+ * we cannot enable IC yet
+ */
+ lis r3, IDC_ENABLE@h /* Enable instruction cache */
+#endif
+ mtspr IC_CST, r3
+
+ /* invalidate all tlb's */
+ /*----------------------------------------------------------------------*/
+
+ tlbia
+ isync
+
+ /*
+ * 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:
+
+ /* initialize some SPRs that are hard to access from C */
+ /*----------------------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_IMMR@h /* pass IMMR as arg1 to C routine */
+ ori r1, r3, CONFIG_SYS_INIT_SP_OFFSET /* set up the stack in internal DPRAM */
+ /* Note: R0 is still 0 here */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ /*
+ * Disable serialized ifetch and show cycles
+ * (i.e. set processor to normal mode).
+ * This is also a silicon bug workaround, see errata
+ */
+
+ li r2, 0x0007
+ mtspr ICTRL, r2
+
+ /* Set up debug mode entry */
+
+ lis r2, CONFIG_SYS_DER@h
+ ori r2, r2, CONFIG_SYS_DER@l
+ mtspr DER, r2
+
+ /* 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 (from Flash) */
+
+ mr r3, r21
+ /* r3: BOOTFLAG */
+ bl board_init_f /* run 1st part of board init code (from Flash) */
+
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. "Never" generated on the 860. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. "Never" generated on the 860. */
+ 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)
+
+ /* No FPU on MPC8xx. This exception is not supposed to happen.
+ */
+ 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)
+
+ /* On the MPC8xx, this is a software emulation interrupt. It occurs
+ * for all unimplemented and illegal instructions.
+ */
+ STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+
+ STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+ STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+
+ STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+ STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+ STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+ STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+ STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+ STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+ STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+
+ STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1d00, InstructionBreakpoint, DebugException)
+ STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+
+ . = 0x2000
+
+/*
+ * 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)
+ mtspr SPRG2,r22 /* r1 is now kernel sp */
+ 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
+
+/* Cache functions.
+*/
+ .globl icache_enable
+icache_enable:
+ SYNC
+ lis r3, IDC_INVALL@h
+ mtspr IC_CST, r3
+ lis r3, IDC_ENABLE@h
+ mtspr IC_CST, r3
+ blr
+
+ .globl icache_disable
+icache_disable:
+ SYNC
+ lis r3, IDC_DISABLE@h
+ mtspr IC_CST, r3
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3, IC_CST
+ srwi r3, r3, 31 /* >>31 => select bit 0 */
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+#if 0
+ SYNC
+#endif
+#if 1
+ lis r3, 0x0400 /* Set cache mode with MMU off */
+ mtspr MD_CTR, r3
+#endif
+
+ lis r3, IDC_INVALL@h
+ mtspr DC_CST, r3
+#if 0
+ lis r3, DC_SFWT@h
+ mtspr DC_CST, r3
+#endif
+ lis r3, IDC_ENABLE@h
+ mtspr DC_CST, r3
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ SYNC
+ lis r3, IDC_DISABLE@h
+ mtspr DC_CST, r3
+ lis r3, IDC_INVALL@h
+ mtspr DC_CST, r3
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3, DC_CST
+ srwi r3, r3, 31 /* >>31 => select bit 0 */
+ blr
+
+ .globl dc_read
+dc_read:
+ mtspr DC_ADR, r3
+ mfspr r3, DC_DAT
+ blr
+
+/*
+ * unsigned int get_immr (unsigned int mask)
+ *
+ * return (mask ? (IMMR & mask) : IMMR);
+ */
+ .globl get_immr
+get_immr:
+ mr r4,r3 /* save mask */
+ mfspr r3, IMMR /* IMMR */
+ cmpwi 0,r4,0 /* mask != 0 ? */
+ beq 4f
+ and r3,r3,r4 /* IMMR & mask */
+4:
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+
+ .globl wr_ic_cst
+wr_ic_cst:
+ mtspr IC_CST, r3
+ blr
+
+ .globl rd_ic_cst
+rd_ic_cst:
+ mfspr r3, IC_CST
+ blr
+
+ .globl wr_ic_adr
+wr_ic_adr:
+ mtspr IC_ADR, r3
+ blr
+
+
+ .globl wr_dc_cst
+wr_dc_cst:
+ mtspr DC_CST, r3
+ blr
+
+ .globl rd_dc_cst
+rd_dc_cst:
+ mfspr r3, DC_CST
+ blr
+
+ .globl wr_dc_adr
+wr_dc_adr:
+ mtspr DC_ADR, r3
+ 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
+ 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 */
+ 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
+ add r0,r0,r11
+ stw r10,0(r3)
+ stw r0,0(r4)
+ bdnz 3b
+4:
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(_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
+
+ mtlr r4 /* restore link register */
+ blr
diff --git a/arch/powerpc/cpu/mpc8xx/traps.c b/arch/powerpc/cpu/mpc8xx/traps.c
new file mode 100644
index 0000000..343dced
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/traps.c
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/* 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
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\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);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+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);
+}
+
+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.
+ */
+ 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
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x000F0000) {
+ case (0x80000000>>12):
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (0x80000000>>13):
+ printf("Transfer error ack signal\n");
+ break;
+ case (0x80000000>>14):
+ printf("Data parity signal\n");
+ break;
+ case (0x80000000>>15):
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ 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);
+}
+
+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;
+}
diff --git a/arch/powerpc/cpu/mpc8xx/upatch.c b/arch/powerpc/cpu/mpc8xx/upatch.c
new file mode 100644
index 0000000..a8cb735
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/upatch.c
@@ -0,0 +1,194 @@
+#include <common.h>
+#include <commproc.h>
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCH) || \
+ defined(CONFIG_SYS_SMC_UCODE_PATCH)
+
+static void UcodeCopy (volatile cpm8xx_t *cpm);
+
+void cpm_load_patch (volatile immap_t *immr)
+{
+ immr->im_cpm.cp_rccr &= ~0x0003; /* Disable microcode program area */
+
+ UcodeCopy ((cpm8xx_t *)&immr->im_cpm); /* Copy ucode patch to DPRAM */
+#ifdef CONFIG_SYS_SPI_UCODE_PATCH
+ {
+ volatile spi_t *spi = (spi_t *) & immr->im_cpm.cp_dparam[PROFF_SPI];
+ /* Activate the microcode per the instructions in the microcode manual */
+ /* NOTE: We're only relocating the SPI parameters (not I2C). */
+ immr->im_cpm.cp_cpmcr1 = 0x802a; /* Write Trap register 1 value */
+ immr->im_cpm.cp_cpmcr2 = 0x8028; /* Write Trap register 2 value */
+ spi->spi_rpbase = CONFIG_SYS_SPI_DPMEM_OFFSET; /* Where to relocte SPI params */
+ }
+#endif
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+ {
+ volatile iic_t *iip = (iic_t *) & immr->im_cpm.cp_dparam[PROFF_IIC];
+ /* Activate the microcode per the instructions in the microcode manual */
+ /* NOTE: We're only relocating the I2C parameters (not SPI). */
+ immr->im_cpm.cp_cpmcr3 = 0x802e; /* Write Trap register 3 value */
+ immr->im_cpm.cp_cpmcr4 = 0x802c; /* Write Trap register 4 value */
+ iip->iic_rpbase = CONFIG_SYS_I2C_DPMEM_OFFSET; /* Where to relocte I2C params */
+ }
+#endif
+
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ {
+ volatile smc_uart_t *up = (smc_uart_t *) & immr->im_cpm.cp_dparam[PROFF_SMC1];
+ /* Activate the microcode per the instructions in the microcode manual */
+ /* NOTE: We're only relocating the SMC parameters. */
+ immr->im_cpm.cp_cpmcr1 = 0x8080; /* Write Trap register 1 value */
+ immr->im_cpm.cp_cpmcr2 = 0x8088; /* Write Trap register 2 value */
+ up->smc_rpbase = CONFIG_SYS_SMC_DPMEM_OFFSET; /* Where to relocte SMC params */
+ }
+#endif
+
+ /*
+ * Enable DPRAM microcode to execute from the first 512 bytes
+ * and a 256 byte extension of DPRAM.
+ */
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ immr->im_cpm.cp_rccr |= 0x0002;
+#else
+ immr->im_cpm.cp_rccr |= 0x0001;
+#endif
+}
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCh)
+static ulong patch_2000[] = {
+ 0x7FFFEFD9, 0x3FFD0000, 0x7FFB49F7, 0x7FF90000,
+ 0x5FEFADF7, 0x5F88ADF7, 0x5FEFAFF7, 0x5F88AFF7,
+ 0x3A9CFBC8, 0x77CAE1BB, 0xF4DE7FAD, 0xABAE9330,
+ 0x4E08FDCF, 0x6E0FAFF8, 0x7CCF76CF, 0xFDAFF9CF,
+ 0xABF88DC8, 0xAB5879F7, 0xB0927383, 0xDFD079F7,
+ 0xB090E6BB, 0xE5BBE74F, 0xB3FA6F0F, 0x6FFB76CE,
+ 0xEE0CF9CF, 0x2BFBEFEF, 0xCFEEF9CF, 0x76CEAD23,
+ 0x90B3DF99, 0x7FDDD0C1, 0x4BF847FD, 0x7CCF76CE,
+ 0xCFEF77CA, 0x7EAF7FAD, 0x7DFDF0B7, 0xEF7A7FCA,
+ 0x77CAFBC8, 0x6079E722, 0xFBC85FFF, 0xDFFF5FB3,
+ 0xFFFBFBC8, 0xF3C894A5, 0xE7C9EDF9, 0x7F9A7FAD,
+ 0x5F36AFE8, 0x5F5BFFDF, 0xDF95CB9E, 0xAF7D5FC3,
+ 0xAFED8C1B, 0x5FC3AFDD, 0x5FC5DF99, 0x7EFDB0B3,
+ 0x5FB3FFFE, 0xABAE5FB3, 0xFFFE5FD0, 0x600BE6BB,
+ 0x600B5FD0, 0xDFC827FB, 0xEFDF5FCA, 0xCFDE3A9C,
+ 0xE7C9EDF9, 0xF3C87F9E, 0x54CA7FED, 0x2D3A3637,
+ 0x756F7E9A, 0xF1CE37EF, 0x2E677FEE, 0x10EBADF8,
+ 0xEFDECFEA, 0xE52F7D9F, 0xE12BF1CE, 0x5F647E9A,
+ 0x4DF8CFEA, 0x5F717D9B, 0xEFEECFEA, 0x5F73E522,
+ 0xEFDE5F73, 0xCFDA0B61, 0x7385DF61, 0xE7C9EDF9,
+ 0x7E9A30D5, 0x1458BFFF, 0xF3C85FFF, 0xDFFFA7F8,
+ 0x5F5BBFFE, 0x7F7D10D0, 0x144D5F33, 0xBFFFAF78,
+ 0x5F5BBFFD, 0xA7F85F33, 0xBFFE77FD, 0x30BD4E08,
+ 0xFDCFE5FF, 0x6E0FAFF8, 0x7EEF7E9F, 0xFDEFF1CF,
+ 0x5F17ABF8, 0x0D5B5F5B, 0xFFEF79F7, 0x309EAFDD,
+ 0x5F3147F8, 0x5F31AFED, 0x7FDD50AF, 0x497847FD,
+ 0x7F9E7FED, 0x7DFD70A9, 0xEF7E7ECE, 0x6BA07F9E,
+ 0x2D227EFD, 0x30DB5F5B, 0xFFFD5F5B, 0xFFEF5F5B,
+ 0xFFDF0C9C, 0xAFED0A9A, 0xAFDD0C37, 0x5F37AFBD,
+ 0x7FBDB081, 0x5F8147F8,
+};
+
+static ulong patch_2F00[] = {
+ 0x3E303430, 0x34343737, 0xABBF9B99, 0x4B4FBDBD,
+ 0x59949334, 0x9FFF37FB, 0x9B177DD9, 0x936956BB,
+ 0xFBDD697B, 0xDD2FD113, 0x1DB9F7BB, 0x36313963,
+ 0x79373369, 0x3193137F, 0x7331737A, 0xF7BB9B99,
+ 0x9BB19795, 0x77FDFD3D, 0x573B773F, 0x737933F7,
+ 0xB991D115, 0x31699315, 0x31531694, 0xBF4FBDBD,
+ 0x35931497, 0x35376956, 0xBD697B9D, 0x96931313,
+ 0x19797937, 0x69350000,
+};
+#else
+
+static ulong patch_2000[] = {
+ 0x3fff0000, 0x3ffd0000, 0x3ffb0000, 0x3ff90000,
+ 0x5fefeff8, 0x5f91eff8, 0x3ff30000, 0x3ff10000,
+ 0x3a11e710, 0xedf0ccb9, 0xf318ed66, 0x7f0e5fe2,
+ 0x7fedbb38, 0x3afe7468, 0x7fedf4d8, 0x8ffbb92d,
+ 0xb83b77fd, 0xb0bb5eb9, 0xdfda7fed, 0x90bde74d,
+ 0x6f0dcbd3, 0xe7decfed, 0xcb50cfed, 0xcfeddf6d,
+ 0x914d4f74, 0x5eaedfcb, 0x9ee0e7df, 0xefbb6ffb,
+ 0xe7ef7f0e, 0x9ee57fed, 0xebb7effa, 0xeb30affb,
+ 0x7fea90b3, 0x7e0cf09f, 0xbffff318, 0x5fffdfff,
+ 0xac35efea, 0x7fce1fc1, 0xe2ff5fbd, 0xaffbe2ff,
+ 0x5fbfaffb, 0xf9a87d0f, 0xaef8770f, 0x7d0fb0a2,
+ 0xeffbbfff, 0xcfef5fba, 0x7d0fbfff, 0x5fba4cf8,
+ 0x7fddd09b, 0x49f847fd, 0x7efdf097, 0x7fedfffd,
+ 0x7dfdf093, 0xef7e7e1e, 0x5fba7f0e, 0x3a11e710,
+ 0xedf0cc87, 0xfb18ad0a, 0x1f85bbb8, 0x74283b7e,
+ 0x7375e4bb, 0x2ab64fb8, 0x5c7de4bb, 0x32fdffbf,
+ 0x5f0843f8, 0x7ce3e1bb, 0xe74f7ded, 0x6f0f4fe8,
+ 0xc7ba32be, 0x73f2efeb, 0x600b4f78, 0xe5bb760b,
+ 0x5388aef8, 0x4ef80b6a, 0xcfef9ee5, 0xabf8751f,
+ 0xefef5b88, 0x741f4fe8, 0x751e760d, 0x7fdb70dd,
+ 0x741cafce, 0xefcc7fce, 0x751e7088, 0x741ce7bb,
+ 0x334ecfed, 0xafdbefeb, 0xe5bb760b, 0x53ceaef8,
+ 0xafe8e7eb, 0x4bf8771e, 0x7e007fed, 0x4fcbe2cc,
+ 0x7fbc3085, 0x7b0f7a0f, 0x34b177fd, 0xb0e75e93,
+ 0xdf313e3b, 0xaf78741f, 0x741f30cc, 0xcfef5f08,
+ 0x741f3e88, 0xafb8771e, 0x5f437fed, 0x0bafe2cc,
+ 0x741ccfec, 0xe5ca53a9, 0x6fcb4f74, 0x5e89df27,
+ 0x2a923d14, 0x4b8fdf0c, 0x751f741c, 0x6c1eeffa,
+ 0xefea7fce, 0x6ffc309a, 0xefec3fca, 0x308fdf0a,
+ 0xadf85e7a, 0xaf7daefd, 0x5e7adf0a, 0x5e7aafdd,
+ 0x761f1088, 0x1e7c7efd, 0x3089fffe, 0x4908fb18,
+ 0x5fffdfff, 0xafbbf0f7, 0x4ef85f43, 0xadf81489,
+ 0x7a0f7089, 0xcfef5089, 0x7a0fdf0c, 0x5e7cafed,
+ 0xbc6e780f, 0xefef780f, 0xefef790f, 0xa7f85eeb,
+ 0xffef790f, 0xefef790f, 0x1489df0a, 0x5e7aadfd,
+ 0x5f09fffb, 0xe79aded9, 0xeff96079, 0x607ae79a,
+ 0xded8eff9, 0x60795edb, 0x607acfef, 0xefefefdf,
+ 0xefbfef7f, 0xeeffedff, 0xebffe7ff, 0xafefafdf,
+ 0xafbfaf7f, 0xaeffadff, 0xabffa7ff, 0x6fef6fdf,
+ 0x6fbf6f7f, 0x6eff6dff, 0x6bff67ff, 0x2fef2fdf,
+ 0x2fbf2f7f, 0x2eff2dff, 0x2bff27ff, 0x4e08fd1f,
+ 0xe5ff6e0f, 0xaff87eef, 0x7e0ffdef, 0xf11f6079,
+ 0xabf8f51e, 0x7e0af11c, 0x37cfae16, 0x7fec909a,
+ 0xadf8efdc, 0xcfeae52f, 0x7d0fe12b, 0xf11c6079,
+ 0x7e0a4df8, 0xcfea5ea0, 0x7d0befec, 0xcfea5ea2,
+ 0xe522efdc, 0x5ea2cfda, 0x4e08fd1f, 0x6e0faff8,
+ 0x7c1f761f, 0xfdeff91f, 0x6079abf8, 0x761cee00,
+ 0xf91f2bfb, 0xefefcfec, 0xf91f6079, 0x761c27fb,
+ 0xefdf5e83, 0xcfdc7fdd, 0x50f84bf8, 0x47fd7c1f,
+ 0x761ccfcf, 0x7eef7fed, 0x7dfd70ef, 0xef7e7f1e,
+ 0x771efb18, 0x6079e722, 0xe6bbe5bb, 0x2e66e5bb,
+ 0x600b2ee1, 0xe2bbe2bb, 0xe2bbe2bb, 0x2f5ee2bb,
+ 0xe2bb2ff9, 0x6079e2bb,
+};
+
+static ulong patch_2F00[] = {
+ 0x30303030, 0x3e3e3030, 0xaf79b9b3, 0xbaa3b979,
+ 0x9693369f, 0x79f79777, 0x97333fff, 0xfb3b9e9f,
+ 0x79b91d11, 0x9e13f3ff, 0x3f9b6bd9, 0xe173d136,
+ 0x695669d1, 0x697b3daf, 0x79b93a3a, 0x3f979f91,
+ 0x379ff976, 0xf99777fd, 0x9779737d, 0xe9d6bbf9,
+ 0xbfffd9df, 0x97f7fd97, 0x6f7b9bff, 0xf9bd9683,
+ 0x397db973, 0xd97b3b9f, 0xd7f9f733, 0x9993bb9e,
+ 0xe1f9ef93, 0x73773337, 0xb936917d, 0x11f87379,
+ 0xb979d336, 0x8b7ded73, 0x1b7d9337, 0x31f3f22f,
+ 0x3f2327ee, 0xeeeeeeee, 0xeeeeeeee, 0xeeeeeeee,
+ 0xeeeeee4b, 0xf4fbdbd2, 0x58bb1878, 0x577fdfd2,
+ 0xd573b773, 0xf7374b4f, 0xbdbd25b8, 0xb177d2d1,
+ 0x7376856b, 0xbfdd687b, 0xdd2fff8f, 0x78ffff8f,
+ 0xf22f0000,
+};
+#endif
+
+static void UcodeCopy (volatile cpm8xx_t *cpm)
+{
+ vu_long *p;
+ int i;
+
+ p = (vu_long *)&(cpm->cp_dpmem[0x0000]);
+ for (i=0; i < sizeof(patch_2000)/4; ++i) {
+ p[i] = patch_2000[i];
+ }
+
+ p = (vu_long *)&(cpm->cp_dpmem[0x0F00]);
+ for (i=0; i < sizeof(patch_2F00)/4; ++i) {
+ p[i] = patch_2F00[i];
+ }
+}
+
+#endif /* CONFIG_SYS_I2C_UCODE_PATCH, CONFIG_SYS_SPI_UCODE_PATCH */
diff --git a/arch/powerpc/cpu/mpc8xx/video.c b/arch/powerpc/cpu/mpc8xx/video.c
new file mode 100644
index 0000000..c79c499
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/video.c
@@ -0,0 +1,1331 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ * (C) Copyright 2002
+ * Wolfgang Denk, wd@denx.de
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* #define DEBUG */
+
+/************************************************************************/
+/* ** HEADER FILES */
+/************************************************************************/
+
+#include <stdarg.h>
+#include <common.h>
+#include <config.h>
+#include <version.h>
+#include <timestamp.h>
+#include <i2c.h>
+#include <linux/types.h>
+#include <stdio_dev.h>
+
+#ifdef CONFIG_VIDEO
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/************************************************************************/
+/* ** DEBUG SETTINGS */
+/************************************************************************/
+
+#if 0
+#define VIDEO_DEBUG_COLORBARS /* Force colorbars output */
+#endif
+
+/************************************************************************/
+/* ** VIDEO MODE SETTINGS */
+/************************************************************************/
+
+#if 0
+#define VIDEO_MODE_EXTENDED /* Allow screen size bigger than visible area */
+#define VIDEO_MODE_NTSC
+#endif
+
+#define VIDEO_MODE_PAL
+
+#if 0
+#define VIDEO_BLINK /* This enables cursor blinking (under construction) */
+#endif
+
+#define VIDEO_INFO /* Show U-Boot information */
+#define VIDEO_INFO_X VIDEO_LOGO_WIDTH+8
+#define VIDEO_INFO_Y 16
+
+/************************************************************************/
+/* ** VIDEO ENCODER CONSTANTS */
+/************************************************************************/
+
+#ifdef CONFIG_VIDEO_ENCODER_AD7176
+
+#include <video_ad7176.h> /* Sets encoder data, mode, and visible and active area */
+
+#define VIDEO_I2C 1
+#define VIDEO_I2C_ADDR CONFIG_VIDEO_ENCODER_AD7176_ADDR
+#endif
+
+#ifdef CONFIG_VIDEO_ENCODER_AD7177
+
+#include <video_ad7177.h> /* Sets encoder data, mode, and visible and active area */
+
+#define VIDEO_I2C 1
+#define VIDEO_I2C_ADDR CONFIG_VIDEO_ENCODER_AD7177_ADDR
+#endif
+
+#ifdef CONFIG_VIDEO_ENCODER_AD7179
+
+#include <video_ad7179.h> /* Sets encoder data, mode, and visible and active area */
+
+#define VIDEO_I2C 1
+#define VIDEO_I2C_ADDR CONFIG_VIDEO_ENCODER_AD7179_ADDR
+#endif
+
+/************************************************************************/
+/* ** VIDEO MODE CONSTANTS */
+/************************************************************************/
+
+#ifdef VIDEO_MODE_EXTENDED
+#define VIDEO_COLS VIDEO_ACTIVE_COLS
+#define VIDEO_ROWS VIDEO_ACTIVE_ROWS
+#else
+#define VIDEO_COLS VIDEO_VISIBLE_COLS
+#define VIDEO_ROWS VIDEO_VISIBLE_ROWS
+#endif
+
+#define VIDEO_PIXEL_SIZE (VIDEO_MODE_BPP/8)
+#define VIDEO_SIZE (VIDEO_ROWS*VIDEO_COLS*VIDEO_PIXEL_SIZE) /* Total size of buffer */
+#define VIDEO_PIX_BLOCKS (VIDEO_SIZE >> 2) /* Number of ints */
+#define VIDEO_LINE_LEN (VIDEO_COLS*VIDEO_PIXEL_SIZE) /* Number of bytes per line */
+#define VIDEO_BURST_LEN (VIDEO_COLS/8)
+
+#ifdef VIDEO_MODE_YUYV
+#define VIDEO_BG_COL 0x80D880D8 /* Background color in YUYV format */
+#else
+#define VIDEO_BG_COL 0xF8F8F8F8 /* Background color in RGB format */
+#endif
+
+/************************************************************************/
+/* ** FONT AND LOGO DATA */
+/************************************************************************/
+
+#include <video_font.h> /* Get font data, width and height */
+
+#ifdef CONFIG_VIDEO_LOGO
+#include <video_logo.h> /* Get logo data, width and height */
+
+#define VIDEO_LOGO_WIDTH DEF_U_BOOT_LOGO_WIDTH
+#define VIDEO_LOGO_HEIGHT DEF_U_BOOT_LOGO_HEIGHT
+#define VIDEO_LOGO_ADDR &u_boot_logo
+#endif
+
+/************************************************************************/
+/* ** VIDEO CONTROLLER CONSTANTS */
+/************************************************************************/
+
+/* VCCR - VIDEO CONTROLLER CONFIGURATION REGISTER */
+
+#define VIDEO_VCCR_VON 0 /* Video controller ON */
+#define VIDEO_VCCR_CSRC 1 /* Clock source */
+#define VIDEO_VCCR_PDF 13 /* Pixel display format */
+#define VIDEO_VCCR_IEN 11 /* Interrupt enable */
+
+/* VSR - VIDEO STATUS REGISTER */
+
+#define VIDEO_VSR_CAS 6 /* Active set */
+#define VIDEO_VSR_EOF 0 /* End of frame */
+
+/* VCMR - VIDEO COMMAND REGISTER */
+
+#define VIDEO_VCMR_BD 0 /* Blank display */
+#define VIDEO_VCMR_ASEL 1 /* Active set selection */
+
+/* VBCB - VIDEO BACKGROUND COLOR BUFFER REGISTER */
+
+#define VIDEO_BCSR4_RESET_BIT 21 /* BCSR4 - Extern video encoder reset */
+#define VIDEO_BCSR4_EXTCLK_BIT 22 /* BCSR4 - Extern clock enable */
+#define VIDEO_BCSR4_VIDLED_BIT 23 /* BCSR4 - Video led disable */
+
+/************************************************************************/
+/* ** CONSOLE CONSTANTS */
+/************************************************************************/
+
+#ifdef CONFIG_VIDEO_LOGO
+#define CONSOLE_ROWS ((VIDEO_ROWS - VIDEO_LOGO_HEIGHT) / VIDEO_FONT_HEIGHT)
+#define VIDEO_LOGO_SKIP (VIDEO_COLS - VIDEO_LOGO_WIDTH)
+#else
+#define CONSOLE_ROWS (VIDEO_ROWS / VIDEO_FONT_HEIGHT)
+#endif
+
+#define CONSOLE_COLS (VIDEO_COLS / VIDEO_FONT_WIDTH)
+#define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
+#define CONSOLE_ROW_FIRST (video_console_address)
+#define CONSOLE_ROW_SECOND (video_console_address + CONSOLE_ROW_SIZE)
+#define CONSOLE_ROW_LAST (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
+#define CONSOLE_SIZE (CONSOLE_ROW_SIZE * CONSOLE_ROWS)
+#define CONSOLE_SCROLL_SIZE (CONSOLE_SIZE - CONSOLE_ROW_SIZE)
+
+/*
+ * Simple color definitions
+ */
+#define CONSOLE_COLOR_BLACK 0
+#define CONSOLE_COLOR_RED 1
+#define CONSOLE_COLOR_GREEN 2
+#define CONSOLE_COLOR_YELLOW 3
+#define CONSOLE_COLOR_BLUE 4
+#define CONSOLE_COLOR_MAGENTA 5
+#define CONSOLE_COLOR_CYAN 6
+#define CONSOLE_COLOR_GREY 13
+#define CONSOLE_COLOR_GREY2 14
+#define CONSOLE_COLOR_WHITE 15 /* Must remain last / highest */
+
+/************************************************************************/
+/* ** BITOPS MACROS */
+/************************************************************************/
+
+#define HISHORT(i) ((i >> 16)&0xffff)
+#define LOSHORT(i) (i & 0xffff)
+#define HICHAR(s) ((i >> 8)&0xff)
+#define LOCHAR(s) (i & 0xff)
+#define HI(c) ((c >> 4)&0xf)
+#define LO(c) (c & 0xf)
+#define SWAPINT(i) (HISHORT(i) | (LOSHORT(i) << 16))
+#define SWAPSHORT(s) (HICHAR(s) | (LOCHAR(s) << 8))
+#define SWAPCHAR(c) (HI(c) | (LO(c) << 4))
+#define BITMASK(b) (1 << (b))
+#define GETBIT(v,b) (((v) & BITMASK(b)) > 0)
+#define SETBIT(v,b,d) (v = (((d)>0) ? (v) | BITMASK(b): (v) & ~BITMASK(b)))
+
+/************************************************************************/
+/* ** STRUCTURES */
+/************************************************************************/
+
+typedef struct {
+ unsigned char V, Y1, U, Y2;
+} tYUYV;
+
+/* This structure is based on the Video Ram in the MPC823. */
+typedef struct VRAM {
+ unsigned hx:2, /* Horizontal sync */
+ vx:2, /* Vertical sync */
+ fx:2, /* Frame */
+ bx:2, /* Blank */
+ res1:6, /* Reserved */
+ vds:2, /* Video Data Select */
+ inter:1, /* Interrupt */
+ res2:2, /* Reserved */
+ lcyc:11, /* Loop/video cycles */
+ lp:1, /* Loop start/end */
+ lst:1; /* Last entry */
+} VRAM;
+
+/************************************************************************/
+/* ** VARIABLES */
+/************************************************************************/
+
+static int
+ video_panning_range_x = 0, /* Video mode invisible pixels x range */
+ video_panning_range_y = 0, /* Video mode invisible pixels y range */
+ video_panning_value_x = 0, /* Video mode x panning value (absolute) */
+ video_panning_value_y = 0, /* Video mode y panning value (absolute) */
+ video_panning_factor_x = 0, /* Video mode x panning value (-127 +127) */
+ video_panning_factor_y = 0, /* Video mode y panning value (-127 +127) */
+ console_col = 0, /* Cursor col */
+ console_row = 0, /* Cursor row */
+ video_palette[16]; /* Our palette */
+
+static const int video_font_draw_table[] =
+ { 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff };
+
+static char
+ video_color_fg = 0, /* Current fg color index (0-15) */
+ video_color_bg = 0, /* Current bg color index (0-15) */
+ video_enable = 0; /* Video has been initialized? */
+
+static void
+ *video_fb_address, /* Frame buffer address */
+ *video_console_address; /* Console frame buffer start address */
+
+/************************************************************************/
+/* ** MEMORY FUNCTIONS (32bit) */
+/************************************************************************/
+
+static void memsetl (int *p, int c, int v)
+{
+ while (c--)
+ *(p++) = v;
+}
+
+static void memcpyl (int *d, int *s, int c)
+{
+ while (c--)
+ *(d++) = *(s++);
+}
+
+/************************************************************************/
+/* ** VIDEO DRAWING AND COLOR FUNCTIONS */
+/************************************************************************/
+
+static int video_maprgb (int r, int g, int b)
+{
+#ifdef VIDEO_MODE_YUYV
+ unsigned int pR, pG, pB;
+ tYUYV YUYV;
+ unsigned int *ret = (unsigned int *) &YUYV;
+
+ /* Transform (0-255) components to (0-100) */
+
+ pR = r * 100 / 255;
+ pG = g * 100 / 255;
+ pB = b * 100 / 255;
+
+ /* Calculate YUV values (0-255) from RGB beetween 0-100 */
+
+ YUYV.Y1 = YUYV.Y2 = 209 * (pR + pG + pB) / 300 + 16;
+ YUYV.U = pR - (pG * 3 / 4) - (pB / 4) + 128;
+ YUYV.V = pB - (pR / 4) - (pG * 3 / 4) + 128;
+ return *ret;
+#endif
+#ifdef VIDEO_MODE_RGB
+ return ((r >> 3) << 11) | ((g > 2) << 6) | (b >> 3);
+#endif
+}
+
+static void video_setpalette (int color, int r, int g, int b)
+{
+ color &= 0xf;
+
+ video_palette[color] = video_maprgb (r, g, b);
+
+ /* Swap values if our panning offset is odd */
+ if (video_panning_value_x & 1)
+ video_palette[color] = SWAPINT (video_palette[color]);
+}
+
+static void video_fill (int color)
+{
+ memsetl (video_fb_address, VIDEO_PIX_BLOCKS, color);
+}
+
+static void video_setfgcolor (int i)
+{
+ video_color_fg = i & 0xf;
+}
+
+static void video_setbgcolor (int i)
+{
+ video_color_bg = i & 0xf;
+}
+
+static int video_pickcolor (int i)
+{
+ return video_palette[i & 0xf];
+}
+
+/* Absolute console plotting functions */
+
+#ifdef VIDEO_BLINK
+static void video_revchar (int xx, int yy)
+{
+ int rows;
+ u8 *dest;
+
+ dest = video_fb_address + yy * VIDEO_LINE_LEN + xx * 2;
+
+ for (rows = VIDEO_FONT_HEIGHT; rows--; dest += VIDEO_LINE_LEN) {
+ switch (VIDEO_FONT_WIDTH) {
+ case 16:
+ ((u32 *) dest)[6] ^= 0xffffffff;
+ ((u32 *) dest)[7] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 12:
+ ((u32 *) dest)[4] ^= 0xffffffff;
+ ((u32 *) dest)[5] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 8:
+ ((u32 *) dest)[2] ^= 0xffffffff;
+ ((u32 *) dest)[3] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 4:
+ ((u32 *) dest)[0] ^= 0xffffffff;
+ ((u32 *) dest)[1] ^= 0xffffffff;
+ }
+ }
+}
+#endif
+
+static void video_drawchars (int xx, int yy, unsigned char *s, int count)
+{
+ u8 *cdat, *dest, *dest0;
+ int rows, offset, c;
+ u32 eorx, fgx, bgx;
+
+ offset = yy * VIDEO_LINE_LEN + xx * 2;
+ dest0 = video_fb_address + offset;
+
+ fgx = video_pickcolor (video_color_fg);
+ bgx = video_pickcolor (video_color_bg);
+
+ if (xx & 1) {
+ fgx = SWAPINT (fgx);
+ bgx = SWAPINT (bgx);
+ }
+
+ eorx = fgx ^ bgx;
+
+ switch (VIDEO_FONT_WIDTH) {
+ case 4:
+ case 8:
+ while (count--) {
+ c = *s;
+ cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
+ for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
+ rows--;
+ dest += VIDEO_LINE_LEN) {
+ u8 bits = *cdat++;
+
+ ((u32 *) dest)[0] =
+ (video_font_draw_table[bits >> 6] & eorx) ^ bgx;
+ ((u32 *) dest)[1] =
+ (video_font_draw_table[bits >> 4 & 3] & eorx) ^ bgx;
+ if (VIDEO_FONT_WIDTH == 8) {
+ ((u32 *) dest)[2] =
+ (video_font_draw_table[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *) dest)[3] =
+ (video_font_draw_table[bits & 3] & eorx) ^ bgx;
+ }
+ }
+ dest0 += VIDEO_FONT_WIDTH * 2;
+ s++;
+ }
+ break;
+ case 12:
+ case 16:
+ while (count--) {
+ cdat = video_fontdata + (*s) * (VIDEO_FONT_HEIGHT << 1);
+ for (rows = VIDEO_FONT_HEIGHT, dest = dest0; rows--;
+ dest += VIDEO_LINE_LEN) {
+ u8 bits = *cdat++;
+
+ ((u32 *) dest)[0] =
+ (video_font_draw_table[bits >> 6] & eorx) ^ bgx;
+ ((u32 *) dest)[1] =
+ (video_font_draw_table[bits >> 4 & 3] & eorx) ^ bgx;
+ ((u32 *) dest)[2] =
+ (video_font_draw_table[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *) dest)[3] =
+ (video_font_draw_table[bits & 3] & eorx) ^ bgx;
+ bits = *cdat++;
+ ((u32 *) dest)[4] =
+ (video_font_draw_table[bits >> 6] & eorx) ^ bgx;
+ ((u32 *) dest)[5] =
+ (video_font_draw_table[bits >> 4 & 3] & eorx) ^ bgx;
+ if (VIDEO_FONT_WIDTH == 16) {
+ ((u32 *) dest)[6] =
+ (video_font_draw_table[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *) dest)[7] =
+ (video_font_draw_table[bits & 3] & eorx) ^ bgx;
+ }
+ }
+ s++;
+ dest0 += VIDEO_FONT_WIDTH * 2;
+ }
+ break;
+ }
+}
+
+static inline void video_drawstring (int xx, int yy, char *s)
+{
+ video_drawchars (xx, yy, (unsigned char *)s, strlen (s));
+}
+
+/* Relative to console plotting functions */
+
+static void video_putchars (int xx, int yy, unsigned char *s, int count)
+{
+#ifdef CONFIG_VIDEO_LOGO
+ video_drawchars (xx, yy + VIDEO_LOGO_HEIGHT, s, count);
+#else
+ video_drawchars (xx, yy, s, count);
+#endif
+}
+
+static void video_putchar (int xx, int yy, unsigned char c)
+{
+#ifdef CONFIG_VIDEO_LOGO
+ video_drawchars (xx, yy + VIDEO_LOGO_HEIGHT, &c, 1);
+#else
+ video_drawchars (xx, yy, &c, 1);
+#endif
+}
+
+static inline void video_putstring (int xx, int yy, unsigned char *s)
+{
+ video_putchars (xx, yy, (unsigned char *)s, strlen ((char *)s));
+}
+
+/************************************************************************/
+/* ** VIDEO CONTROLLER LOW-LEVEL FUNCTIONS */
+/************************************************************************/
+
+#if !defined(CONFIG_RRVISION)
+static void video_mode_dupefield (VRAM * source, VRAM * dest, int entries)
+{
+ int i;
+
+ for (i = 0; i < entries; i++) {
+ dest[i] = source[i]; /* Copy the entire record */
+ dest[i].fx = (!dest[i].fx) * 3; /* Negate field bit */
+ }
+
+ dest[0].lcyc++; /* Add a cycle to the first entry */
+ dest[entries - 1].lst = 1; /* Set end of ram entries */
+}
+#endif
+
+static void inline video_mode_addentry (VRAM * vr,
+ int Hx, int Vx, int Fx, int Bx,
+ int VDS, int INT, int LCYC, int LP, int LST)
+{
+ vr->hx = Hx;
+ vr->vx = Vx;
+ vr->fx = Fx;
+ vr->bx = Bx;
+ vr->vds = VDS;
+ vr->inter = INT;
+ vr->lcyc = LCYC;
+ vr->lp = LP;
+ vr->lst = LST;
+}
+
+#define ADDENTRY(a,b,c,d,e,f,g,h,i) video_mode_addentry(&vr[entry++],a,b,c,d,e,f,g,h,i)
+
+static int video_mode_generate (void)
+{
+ immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ VRAM *vr = (VRAM *) (((void *) immap) + 0xb00); /* Pointer to the VRAM table */
+ int DX, X1, X2, DY, Y1, Y2, entry = 0, fifo;
+
+ /* CHECKING PARAMETERS */
+
+ if (video_panning_factor_y < -128)
+ video_panning_factor_y = -128;
+
+ if (video_panning_factor_y > 128)
+ video_panning_factor_y = 128;
+
+ if (video_panning_factor_x < -128)
+ video_panning_factor_x = -128;
+
+ if (video_panning_factor_x > 128)
+ video_panning_factor_x = 128;
+
+ /* Setting panning */
+
+ DX = video_panning_range_x = (VIDEO_ACTIVE_COLS - VIDEO_COLS) * 2;
+ DY = video_panning_range_y = (VIDEO_ACTIVE_ROWS - VIDEO_ROWS) / 2;
+
+ video_panning_value_x = (video_panning_factor_x + 128) * DX / 256;
+ video_panning_value_y = (video_panning_factor_y + 128) * DY / 256;
+
+ /* We assume these are burst units (multiplied by 2, we need it pari) */
+ X1 = video_panning_value_x & 0xfffe;
+ X2 = DX - X1;
+
+ /* We assume these are field line units (divided by 2, we need it pari) */
+ Y1 = video_panning_value_y & 0xfffe;
+ Y2 = DY - Y1;
+
+ debug("X1=%d, X2=%d, Y1=%d, Y2=%d, DX=%d, DY=%d VIDEO_COLS=%d \n",
+ X1, X2, Y1, Y2, DX, DY, VIDEO_COLS);
+
+#ifdef VIDEO_MODE_NTSC
+/*
+ * Hx Vx Fx Bx VDS INT LCYC LP LST
+ *
+ * Retrace blanking
+ */
+ ADDENTRY (0, 0, 3, 0, 1, 0, 3, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 243, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+/*
+ * Vertical blanking
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 18, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 243, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+/*
+ * Odd field active area (TOP)
+ */
+ if (Y1 > 0) {
+ ADDENTRY (0, 0, 0, 0, 1, 0, Y1, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+ }
+/*
+ * Odd field active area
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 240 - DY, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 8 + X1, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 0, 0, VIDEO_COLS * 2, 0, 0);
+
+ if (X2 > 0)
+ ADDENTRY (3, 0, 0, 3, 1, 0, X2, 0, 0);
+
+ ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+
+/*
+ * Odd field active area (BOTTOM)
+ */
+ if (Y1 > 0) {
+ ADDENTRY (0, 0, 0, 0, 1, 0, Y2, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+ }
+/*
+ * Vertical blanking
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 4, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 243, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+/*
+ * Vertical blanking
+ */
+ ADDENTRY (0, 0, 3, 0, 1, 0, 19, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 243, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+/*
+ * Even field active area (TOP)
+ */
+ if (Y1 > 0) {
+ ADDENTRY (0, 0, 3, 0, 1, 0, Y1, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 3, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+ }
+/*
+ * Even field active area (CENTER)
+ */
+ ADDENTRY (0, 0, 3, 0, 1, 0, 240 - DY, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 3, 3, 1, 0, 8 + X1, 0, 0);
+ ADDENTRY (3, 0, 3, 3, 0, 0, VIDEO_COLS * 2, 0, 0);
+
+ if (X2 > 0)
+ ADDENTRY (3, 0, 3, 3, 1, 0, X2, 0, 0);
+
+ ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+/*
+ * Even field active area (BOTTOM)
+ */
+ if (Y1 > 0) {
+ ADDENTRY (0, 0, 3, 0, 1, 0, Y2, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 3, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+ }
+/*
+ * Vertical blanking
+ */
+ ADDENTRY (0, 0, 3, 0, 1, 0, 1, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 243, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 1, 32, 1, 1);
+#endif
+
+#ifdef VIDEO_MODE_PAL
+
+#if defined(CONFIG_RRVISION)
+
+#define HPW 160 /* horizontal pulse width (was 139) */
+#define VPW 2 /* vertical pulse width */
+#define HBP 104 /* horizontal back porch (was 112) */
+#define VBP 19 /* vertical back porch (was 19) */
+#define VID_R 240 /* number of rows */
+
+ debug ("[VIDEO CTRL] Starting to add controller entries...");
+/*
+ * Even field
+ */
+ ADDENTRY (0, 3, 0, 3, 1, 0, 2, 0, 0);
+ ADDENTRY (0, 0, 0, 3, 1, 0, HPW, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 0, 0);
+
+ ADDENTRY (0, 0, 0, 3, 1, 0, VPW, 1, 0);
+ ADDENTRY (0, 0, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+
+ ADDENTRY (0, 3, 0, 3, 1, 0, VBP, 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+/*
+ * Active area
+ */
+ ADDENTRY (0, 3, 0, 3, 1, 0, VID_R , 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 0, 0, VIDEO_COLS*2, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, 72, 1, 1);
+
+ ADDENTRY (0, 3, 0, 3, 1, 0, 51, 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP +(VIDEO_COLS * 2) + 72 , 1, 0);
+/*
+ * Odd field
+ */
+ ADDENTRY (0, 3, 0, 3, 1, 0, 2, 0, 0);
+ ADDENTRY (0, 0, 0, 3, 1, 0, HPW, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 0, 0);
+
+ ADDENTRY (0, 0, 0, 3, 1, 0, VPW+1, 1, 0);
+ ADDENTRY (0, 0, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+
+ ADDENTRY (0, 3, 0, 3, 1, 0, VBP, 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+/*
+ * Active area
+ */
+ ADDENTRY (0, 3, 0, 3, 1, 0, VID_R , 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 0, 0, VIDEO_COLS*2, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, 72, 1, 1);
+
+ ADDENTRY (0, 3, 0, 3, 1, 0, 51, 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP +(VIDEO_COLS * 2) + 72 , 1, 0);
+
+ debug ("done\n");
+
+#else /* !CONFIG_RRVISION */
+
+/*
+ * Hx Vx Fx Bx VDS INT LCYC LP LST
+ *
+ * vertical; blanking
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 22, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 263, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+/*
+ * active area (TOP)
+ */
+ if (Y1 > 0) {
+ ADDENTRY (0, 0, 0, 0, 1, 0, Y1, 1, 0); /* 11? */
+ ADDENTRY (3, 0, 0, 0, 1, 0, 255, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+ }
+/*
+ * field active area (CENTER)
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 288 - DY, 1, 0); /* 265? */
+ ADDENTRY (3, 0, 0, 0, 1, 0, 255, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 8 + X1, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 0, 0, VIDEO_COLS * 2, 0, 0);
+
+ if (X2 > 0)
+ ADDENTRY (3, 0, 0, 1, 1, 0, X2, 0, 0);
+
+ ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+/*
+ * field active area (BOTTOM)
+ */
+ if (Y2 > 0) {
+ ADDENTRY (0, 0, 0, 0, 1, 0, Y2, 1, 0); /* 12? */
+ ADDENTRY (3, 0, 0, 0, 1, 0, 255, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+ }
+/*
+ * field vertical; blanking
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 2, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 263, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+/*
+ * Create the other field (like this, but whit other field selected,
+ * one more cycle loop and a last identifier)
+ */
+ video_mode_dupefield (vr, &vr[entry], entry);
+#endif /* CONFIG_RRVISION */
+
+#endif /* VIDEO_MODE_PAL */
+
+ /* See what FIFO are we using */
+ fifo = GETBIT (immap->im_vid.vid_vsr, VIDEO_VSR_CAS);
+
+ /* Set number of lines and burst (only one frame for now) */
+ if (fifo) {
+ immap->im_vid.vid_vfcr0 = VIDEO_BURST_LEN |
+ (VIDEO_BURST_LEN << 8) | ((VIDEO_ROWS / 2) << 19);
+ } else {
+ immap->im_vid.vid_vfcr1 = VIDEO_BURST_LEN |
+ (VIDEO_BURST_LEN << 8) | ((VIDEO_ROWS / 2) << 19);
+ }
+
+ SETBIT (immap->im_vid.vid_vcmr, VIDEO_VCMR_ASEL, !fifo);
+
+/*
+ * Wait until changes are applied (not done)
+ * while (GETBIT(immap->im_vid.vid_vsr, VIDEO_VSR_CAS) == fifo) ;
+ */
+
+ /* Return number of VRAM entries */
+ return entry * 2;
+}
+
+static void video_encoder_init (void)
+{
+#ifdef VIDEO_I2C
+ int rc;
+
+ /* Initialize the I2C */
+ debug ("[VIDEO ENCODER] Initializing I2C bus...\n");
+ i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+#ifdef CONFIG_FADS
+ /* Reset ADV7176 chip */
+ debug ("[VIDEO ENCODER] Resetting encoder...\n");
+ (*(int *) BCSR4) &= ~(1 << 21);
+
+ /* Wait for 5 ms inside the reset */
+ debug ("[VIDEO ENCODER] Waiting for encoder reset...\n");
+ udelay (5000);
+
+ /* Take ADV7176 out of reset */
+ (*(int *) BCSR4) |= 1 << 21;
+
+ /* Wait for 5 ms after the reset */
+ udelay (5000);
+#endif /* CONFIG_FADS */
+
+ /* Send configuration */
+#ifdef DEBUG
+ {
+ int i;
+
+ puts ("[VIDEO ENCODER] Configuring the encoder...\n");
+
+ printf ("Sending %zu bytes (@ %08lX) to I2C 0x%lX:\n ",
+ sizeof(video_encoder_data),
+ (ulong)video_encoder_data,
+ (ulong)VIDEO_I2C_ADDR);
+ for (i=0; i<sizeof(video_encoder_data); ++i) {
+ printf(" %02X", video_encoder_data[i]);
+ }
+ putc ('\n');
+ }
+#endif /* DEBUG */
+
+ if ((rc = i2c_write (VIDEO_I2C_ADDR, 0, 1,
+ video_encoder_data,
+ sizeof(video_encoder_data))) != 0) {
+ printf ("i2c_send error: rc=%d\n", rc);
+ return;
+ }
+#endif /* VIDEO_I2C */
+ return;
+}
+
+static void video_ctrl_init (void *memptr)
+{
+ immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ video_fb_address = memptr;
+
+ /* Set background */
+ debug ("[VIDEO CTRL] Setting background color...\n");
+ immap->im_vid.vid_vbcb = VIDEO_BG_COL;
+
+ /* Show the background */
+ debug ("[VIDEO CTRL] Forcing background...\n");
+ SETBIT (immap->im_vid.vid_vcmr, VIDEO_VCMR_BD, 1);
+
+ /* Turn off video controller */
+ debug ("[VIDEO CTRL] Turning off video controller...\n");
+ SETBIT (immap->im_vid.vid_vccr, VIDEO_VCCR_VON, 0);
+
+#ifdef CONFIG_FADS
+ /* Turn on Video Port LED */
+ debug ("[VIDEO CTRL] Turning off video port led...\n");
+ SETBIT (*(int *) BCSR4, VIDEO_BCSR4_VIDLED_BIT, 1);
+
+ /* Disable internal clock */
+ debug ("[VIDEO CTRL] Disabling internal clock...\n");
+ SETBIT (*(int *) BCSR4, VIDEO_BCSR4_EXTCLK_BIT, 0);
+#endif
+
+ /* Generate and make active a new video mode */
+ debug ("[VIDEO CTRL] Generating video mode...\n");
+ video_mode_generate ();
+
+ /* Start of frame buffer (even and odd frame, to make it working with */
+ /* any selected active set) */
+ debug ("[VIDEO CTRL] Setting frame buffer address...\n");
+ immap->im_vid.vid_vfaa1 =
+ immap->im_vid.vid_vfaa0 = (u32) video_fb_address;
+ immap->im_vid.vid_vfba1 =
+ immap->im_vid.vid_vfba0 =
+ (u32) video_fb_address + VIDEO_LINE_LEN;
+
+ /* YUV, Big endian, SHIFT/CLK/CLK input (BEFORE ENABLING 27MHZ EXT CLOCK) */
+ debug ("[VIDEO CTRL] Setting pixel mode and clocks...\n");
+ immap->im_vid.vid_vccr = 0x2042;
+
+ /* Configure port pins */
+ debug ("[VIDEO CTRL] Configuring input/output pins...\n");
+ immap->im_ioport.iop_pdpar = 0x1fff;
+ immap->im_ioport.iop_pddir = 0x0000;
+
+#ifdef CONFIG_FADS
+ /* Turn on Video Port Clock - ONLY AFTER SET VCCR TO ENABLE EXTERNAL CLOCK */
+ debug ("[VIDEO CTRL] Turning on video clock...\n");
+ SETBIT (*(int *) BCSR4, VIDEO_BCSR4_EXTCLK_BIT, 1);
+
+ /* Turn on Video Port LED */
+ debug ("[VIDEO CTRL] Turning on video port led...\n");
+ SETBIT (*(int *) BCSR4, VIDEO_BCSR4_VIDLED_BIT, 0);
+#endif
+#ifdef CONFIG_RRVISION
+ debug ("PC5->Output(1): enable PAL clock");
+ immap->im_ioport.iop_pcpar &= ~(0x0400);
+ immap->im_ioport.iop_pcdir |= 0x0400 ;
+ immap->im_ioport.iop_pcdat |= 0x0400 ;
+ debug ("PDPAR=0x%04X PDDIR=0x%04X PDDAT=0x%04X\n",
+ immap->im_ioport.iop_pdpar,
+ immap->im_ioport.iop_pddir,
+ immap->im_ioport.iop_pddat);
+ debug ("PCPAR=0x%04X PCDIR=0x%04X PCDAT=0x%04X\n",
+ immap->im_ioport.iop_pcpar,
+ immap->im_ioport.iop_pcdir,
+ immap->im_ioport.iop_pcdat);
+#endif /* CONFIG_RRVISION */
+
+ /* Blanking the screen. */
+ debug ("[VIDEO CTRL] Blanking the screen...\n");
+ video_fill (VIDEO_BG_COL);
+
+ /*
+ * Turns on Aggressive Mode. Normally, turning on the caches
+ * will cause the screen to flicker when the caches try to
+ * fill. This gives the FIFO's for the Video Controller
+ * higher priority and prevents flickering because of
+ * underrun. This may still be an issue when using FLASH,
+ * since accessing data from Flash is so slow.
+ */
+ debug ("[VIDEO CTRL] Turning on aggressive mode...\n");
+ immap->im_siu_conf.sc_sdcr = 0x40;
+
+ /* Turn on video controller */
+ debug ("[VIDEO CTRL] Turning on video controller...\n");
+ SETBIT (immap->im_vid.vid_vccr, VIDEO_VCCR_VON, 1);
+
+ /* Show the display */
+ debug ("[VIDEO CTRL] Enabling the video...\n");
+ SETBIT (immap->im_vid.vid_vcmr, VIDEO_VCMR_BD, 0);
+}
+
+/************************************************************************/
+/* ** CONSOLE FUNCTIONS */
+/************************************************************************/
+
+static void console_scrollup (void)
+{
+ /* Copy up rows ignoring the first one */
+ memcpyl (CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND, CONSOLE_SCROLL_SIZE >> 2);
+
+ /* Clear the last one */
+ memsetl (CONSOLE_ROW_LAST, CONSOLE_ROW_SIZE >> 2, VIDEO_BG_COL);
+}
+
+static inline void console_back (void)
+{
+ console_col--;
+
+ if (console_col < 0) {
+ console_col = CONSOLE_COLS - 1;
+ console_row--;
+ if (console_row < 0)
+ console_row = 0;
+ }
+
+ video_putchar ( console_col * VIDEO_FONT_WIDTH,
+ console_row * VIDEO_FONT_HEIGHT, ' ');
+}
+
+static inline void console_newline (void)
+{
+ console_row++;
+ console_col = 0;
+
+ /* Check if we need to scroll the terminal */
+ if (console_row >= CONSOLE_ROWS) {
+ /* Scroll everything up */
+ console_scrollup ();
+
+ /* Decrement row number */
+ console_row--;
+ }
+}
+
+void video_putc (const char c)
+{
+ if (!video_enable) {
+ serial_putc (c);
+ return;
+ }
+
+ switch (c) {
+ case 13: /* Simply ignore this */
+ break;
+
+ case '\n': /* Next line, please */
+ console_newline ();
+ break;
+
+ case 9: /* Tab (8 chars alignment) */
+ console_col |= 0x0008; /* Next 8 chars boundary */
+ console_col &= ~0x0007; /* Set this bit to zero */
+
+ if (console_col >= CONSOLE_COLS)
+ console_newline ();
+ break;
+
+ case 8: /* Eat last character */
+ console_back ();
+ break;
+
+ default: /* Add to the console */
+ video_putchar ( console_col * VIDEO_FONT_WIDTH,
+ console_row * VIDEO_FONT_HEIGHT, c);
+ console_col++;
+ /* Check if we need to go to next row */
+ if (console_col >= CONSOLE_COLS)
+ console_newline ();
+ }
+}
+
+void video_puts (const char *s)
+{
+ int count = strlen (s);
+
+ if (!video_enable)
+ while (count--)
+ serial_putc (*s++);
+ else
+ while (count--)
+ video_putc (*s++);
+}
+
+/************************************************************************/
+/* ** CURSOR BLINKING FUNCTIONS */
+/************************************************************************/
+
+#ifdef VIDEO_BLINK
+
+#define BLINK_TIMER_ID 0
+#define BLINK_TIMER_HZ 2
+
+static unsigned char blink_enabled = 0;
+static timer_t blink_timer;
+
+static void blink_update (void)
+{
+ static int blink_row = -1, blink_col = -1, blink_old = 0;
+
+ /* Check if we have a new position to invert */
+ if ((console_row != blink_row) || (console_col != blink_col)) {
+ /* Check if we need to reverse last character */
+ if (blink_old)
+ video_revchar ( blink_col * VIDEO_FONT_WIDTH,
+ (blink_row
+#ifdef CONFIG_VIDEO_LOGO
+ + VIDEO_LOGO_HEIGHT
+#endif
+ ) * VIDEO_FONT_HEIGHT);
+
+ /* Update values */
+ blink_row = console_row;
+ blink_col = console_col;
+ blink_old = 0;
+ }
+
+/* Reverse this character */
+ blink_old = !blink_old;
+ video_revchar ( console_col * VIDEO_FONT_WIDTH,
+ (console_row
+#ifdef CONFIG_VIDEO_LOGO
+ + VIDEO_LOGO_HEIGHT
+#endif
+ ) * VIDEO_FONT_HEIGHT);
+
+}
+
+/*
+ * Handler for blinking cursor
+ */
+static void blink_handler (void *arg)
+{
+/* Blink */
+ blink_update ();
+/* Ack the timer */
+ timer_ack (&blink_timer);
+}
+
+int blink_set (int blink)
+{
+ int ret = blink_enabled;
+
+ if (blink)
+ timer_enable (&blink_timer);
+ else
+ timer_disable (&blink_timer);
+
+ blink_enabled = blink;
+
+ return ret;
+}
+
+static inline void blink_close (void)
+{
+ timer_close (&blink_timer);
+}
+
+static inline void blink_init (void)
+{
+ timer_init (&blink_timer,
+ BLINK_TIMER_ID, BLINK_TIMER_HZ,
+ blink_handler);
+}
+#endif
+
+/************************************************************************/
+/* ** LOGO PLOTTING FUNCTIONS */
+/************************************************************************/
+
+#ifdef CONFIG_VIDEO_LOGO
+void easylogo_plot (fastimage_t * image, void *screen, int width, int x,
+ int y)
+{
+ int skip = width - image->width, xcount, ycount = image->height;
+
+#ifdef VIDEO_MODE_YUYV
+ ushort *source = (ushort *) image->data;
+ ushort *dest = (ushort *) screen + y * width + x;
+
+ while (ycount--) {
+ xcount = image->width;
+ while (xcount--)
+ *dest++ = *source++;
+ dest += skip;
+ }
+#endif
+#ifdef VIDEO_MODE_RGB
+ unsigned char
+ *source = (unsigned short *) image->data,
+ *dest = (unsigned short *) screen + ((y * width) + x) * 3;
+
+ while (ycount--) {
+ xcount = image->width * 3;
+ memcpy (dest, source, xcount);
+ source += xcount;
+ dest += ycount;
+ }
+#endif
+}
+
+static void *video_logo (void)
+{
+ u16 *screen = video_fb_address, width = VIDEO_COLS;
+#ifdef VIDEO_INFO
+# ifndef CONFIG_FADS
+ char temp[32];
+# endif
+ char info[80];
+#endif /* VIDEO_INFO */
+
+ easylogo_plot (VIDEO_LOGO_ADDR, screen, width, 0, 0);
+
+#ifdef VIDEO_INFO
+ sprintf (info, "%s (%s - %s) ",
+ U_BOOT_VERSION, U_BOOT_DATE, U_BOOT_TIME);
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y, info);
+
+ sprintf (info, "(C) 2002 DENX Software Engineering");
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
+ info);
+
+ sprintf (info, " Wolfgang DENK, wd@denx.de");
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT * 2,
+ info);
+#ifndef CONFIG_FADS /* all normal boards */
+ /* leave one blank line */
+
+ sprintf (info, "MPC823 CPU at %s MHz, %ld MB RAM, %ld MB Flash",
+ strmhz(temp, gd->cpu_clk),
+ gd->ram_size >> 20,
+ gd->bd->bi_flashsize >> 20 );
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT * 4,
+ info);
+#else /* FADS :-( */
+ sprintf (info, "MPC823 CPU at 50 MHz on FADS823 board");
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
+ info);
+
+ sprintf (info, "2MB FLASH - 8MB DRAM - 4MB SRAM");
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT * 2,
+ info);
+#endif
+#endif
+
+ return video_fb_address + VIDEO_LOGO_HEIGHT * VIDEO_LINE_LEN;
+}
+#endif
+
+/************************************************************************/
+/* ** VIDEO HIGH-LEVEL FUNCTIONS */
+/************************************************************************/
+
+static int video_init (void *videobase)
+{
+ /* Initialize the encoder */
+ debug ("[VIDEO] Initializing video encoder...\n");
+ video_encoder_init ();
+
+ /* Initialize the video controller */
+ debug ("[VIDEO] Initializing video controller at %08x...\n",
+ (int) videobase);
+ video_ctrl_init (videobase);
+
+ /* Setting the palette */
+ video_setpalette (CONSOLE_COLOR_BLACK, 0, 0, 0);
+ video_setpalette (CONSOLE_COLOR_RED, 0xFF, 0, 0);
+ video_setpalette (CONSOLE_COLOR_GREEN, 0, 0xFF, 0);
+ video_setpalette (CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0);
+ video_setpalette (CONSOLE_COLOR_BLUE, 0, 0, 0xFF);
+ video_setpalette (CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF);
+ video_setpalette (CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF);
+ video_setpalette (CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA);
+ video_setpalette (CONSOLE_COLOR_GREY2, 0xF8, 0xF8, 0xF8);
+ video_setpalette (CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF);
+
+#ifndef CONFIG_SYS_WHITE_ON_BLACK
+ video_setfgcolor (CONSOLE_COLOR_BLACK);
+ video_setbgcolor (CONSOLE_COLOR_GREY2);
+#else
+ video_setfgcolor (CONSOLE_COLOR_GREY2);
+ video_setbgcolor (CONSOLE_COLOR_BLACK);
+#endif /* CONFIG_SYS_WHITE_ON_BLACK */
+
+#ifdef CONFIG_VIDEO_LOGO
+ /* Paint the logo and retrieve tv base address */
+ debug ("[VIDEO] Drawing the logo...\n");
+ video_console_address = video_logo ();
+#else
+ video_console_address = video_fb_address;
+#endif
+
+#ifdef VIDEO_BLINK
+ /* Enable the blinking (under construction) */
+ blink_init ();
+ blink_set (0); /* To Fix! */
+#endif
+
+ /* Initialize the console */
+ console_col = 0;
+ console_row = 0;
+ video_enable = 1;
+
+#ifdef VIDEO_MODE_PAL
+# define VIDEO_MODE_TMP1 "PAL"
+#endif
+#ifdef VIDEO_MODE_NTSC
+# define VIDEO_MODE_TMP1 "NTSC"
+#endif
+#ifdef VIDEO_MODE_YUYV
+# define VIDEO_MODE_TMP2 "YCbYCr"
+#endif
+#ifdef VIDEO_MODE_RGB
+# define VIDEO_MODE_TMP2 "RGB"
+#endif
+ debug ( VIDEO_MODE_TMP1
+ " %dx%dx%d (" VIDEO_MODE_TMP2 ") on %s - console %dx%d\n",
+ VIDEO_COLS, VIDEO_ROWS, VIDEO_MODE_BPP,
+ VIDEO_ENCODER_NAME, CONSOLE_COLS, CONSOLE_ROWS);
+ return 0;
+}
+
+int drv_video_init (void)
+{
+ int error, devices = 1;
+
+ struct stdio_dev videodev;
+
+ video_init ((void *)(gd->fb_base)); /* Video initialization */
+
+/* Device initialization */
+
+ memset (&videodev, 0, sizeof (videodev));
+
+ strcpy (videodev.name, "video");
+ videodev.ext = DEV_EXT_VIDEO; /* Video extensions */
+ videodev.flags = DEV_FLAGS_OUTPUT; /* Output only */
+ videodev.putc = video_putc; /* 'putc' function */
+ videodev.puts = video_puts; /* 'puts' function */
+
+ error = stdio_register (&videodev);
+
+ return (error == 0) ? devices : error;
+}
+
+/************************************************************************/
+/* ** ROM capable initialization part - needed to reserve FB memory */
+/************************************************************************/
+
+/*
+ * This is called early in the system initialization to grab memory
+ * for the video controller.
+ * Returns new address for monitor, after reserving video buffer memory
+ *
+ * Note that this is running from ROM, so no write access to global data.
+ */
+ulong video_setmem (ulong addr)
+{
+ /* Allocate pages for the frame buffer. */
+ addr -= VIDEO_SIZE;
+
+ debug ("Reserving %dk for Video Framebuffer at: %08lx\n",
+ VIDEO_SIZE>>10, addr);
+
+ return (addr);
+}
+
+#endif
diff --git a/arch/powerpc/cpu/mpc8xx/wlkbd.c b/arch/powerpc/cpu/mpc8xx/wlkbd.c
new file mode 100644
index 0000000..13009e2
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/wlkbd.c
@@ -0,0 +1,36 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+
+#ifdef CONFIG_WL_4PPM_KEYBOARD
+
+/* WIP: Wireless keyboard on SMC
+ */
+int drv_wlkbd_init (void)
+{
+ return 0 ;
+}
+
+#endif /* CONFIG_WL_4PPM_KEYBOARD */