summaryrefslogtreecommitdiff
path: root/post/cpu/ppc4xx
diff options
context:
space:
mode:
Diffstat (limited to 'post/cpu/ppc4xx')
-rw-r--r--post/cpu/ppc4xx/Makefile29
-rw-r--r--post/cpu/ppc4xx/cache.c126
-rw-r--r--post/cpu/ppc4xx/cache_4xx.S492
-rw-r--r--post/cpu/ppc4xx/ether.c402
-rw-r--r--post/cpu/ppc4xx/fpu.c59
-rw-r--r--post/cpu/ppc4xx/spr.c182
-rw-r--r--post/cpu/ppc4xx/uart.c381
-rw-r--r--post/cpu/ppc4xx/watchdog.c71
8 files changed, 1742 insertions, 0 deletions
diff --git a/post/cpu/ppc4xx/Makefile b/post/cpu/ppc4xx/Makefile
new file mode 100644
index 0000000..f1034da
--- /dev/null
+++ b/post/cpu/ppc4xx/Makefile
@@ -0,0 +1,29 @@
+#
+# (C) Copyright 2002-2007
+# 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
+#
+
+LIB = libpostppc4xx.a
+
+AOBJS = cache_4xx.o
+COBJS = cache.o ether.o fpu.o spr.o uart.o watchdog.o
+
+include $(TOPDIR)/post/rules.mk
diff --git a/post/cpu/ppc4xx/cache.c b/post/cpu/ppc4xx/cache.c
new file mode 100644
index 0000000..109ca1f
--- /dev/null
+++ b/post/cpu/ppc4xx/cache.c
@@ -0,0 +1,126 @@
+/*
+ * (C) Copyright 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Author: Igor Lisitsin <igor@emcraft.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+/* Cache test
+ *
+ * This test verifies the CPU data and instruction cache using
+ * several test scenarios.
+ */
+
+#ifdef CONFIG_POST
+
+#include <post.h>
+
+#if CONFIG_POST & CFG_POST_CACHE
+
+#include <asm/mmu.h>
+#include <watchdog.h>
+
+#define CACHE_POST_SIZE 1024
+
+void program_tlb(u32 phys_addr, u32 virt_addr, u32 size, u32 tlb_word2_i_value);
+
+int cache_post_test1 (int tlb, void *p, int size);
+int cache_post_test2 (int tlb, void *p, int size);
+int cache_post_test3 (int tlb, void *p, int size);
+int cache_post_test4 (int tlb, void *p, int size);
+int cache_post_test5 (int tlb, void *p, int size);
+int cache_post_test6 (int tlb, void *p, int size);
+
+static int tlb = -1; /* index to the victim TLB entry */
+
+#ifdef CONFIG_440
+static unsigned char testarea[CACHE_POST_SIZE]
+__attribute__((__aligned__(CACHE_POST_SIZE)));
+#endif
+
+int cache_post_test (int flags)
+{
+ void* virt = (void*)CFG_POST_CACHE_ADDR;
+ int ints;
+ int res = 0;
+
+ /*
+ * All 44x variants deal with cache management differently
+ * because they have the address translation always enabled.
+ * The 40x ppc's don't use address translation in U-Boot at all,
+ * so we have to distinguish here between 40x and 44x.
+ */
+#ifdef CONFIG_440
+ int word0, i;
+
+ if (tlb < 0) {
+ /*
+ * Allocate a new TLB entry, since we are going to modify
+ * the write-through and caching inhibited storage attributes.
+ */
+ program_tlb((u32)testarea, (u32)virt,
+ CACHE_POST_SIZE, TLB_WORD2_I_ENABLE);
+
+ /* Find the TLB entry */
+ for (i = 0;; i++) {
+ if (i >= PPC4XX_TLB_SIZE) {
+ printf ("Failed to program tlb entry\n");
+ return -1;
+ }
+ word0 = mftlb1(i);
+ if (TLB_WORD0_EPN_DECODE(word0) == (u32)virt) {
+ tlb = i;
+ break;
+ }
+ }
+ }
+#endif
+ ints = disable_interrupts ();
+
+ WATCHDOG_RESET ();
+ if (res == 0)
+ res = cache_post_test1 (tlb, virt, CACHE_POST_SIZE);
+ WATCHDOG_RESET ();
+ if (res == 0)
+ res = cache_post_test2 (tlb, virt, CACHE_POST_SIZE);
+ WATCHDOG_RESET ();
+ if (res == 0)
+ res = cache_post_test3 (tlb, virt, CACHE_POST_SIZE);
+ WATCHDOG_RESET ();
+ if (res == 0)
+ res = cache_post_test4 (tlb, virt, CACHE_POST_SIZE);
+ WATCHDOG_RESET ();
+ if (res == 0)
+ res = cache_post_test5 (tlb, virt, CACHE_POST_SIZE);
+ WATCHDOG_RESET ();
+ if (res == 0)
+ res = cache_post_test6 (tlb, virt, CACHE_POST_SIZE);
+
+ if (ints)
+ enable_interrupts ();
+
+ return res;
+}
+
+#endif /* CONFIG_POST & CFG_POST_CACHE */
+#endif /* CONFIG_POST */
diff --git a/post/cpu/ppc4xx/cache_4xx.S b/post/cpu/ppc4xx/cache_4xx.S
new file mode 100644
index 0000000..d5cb075
--- /dev/null
+++ b/post/cpu/ppc4xx/cache_4xx.S
@@ -0,0 +1,492 @@
+/*
+ * (C) Copyright 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Author: Igor Lisitsin <igor@emcraft.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+
+#ifdef CONFIG_POST
+
+#include <post.h>
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#if CONFIG_POST & CFG_POST_CACHE
+
+ .text
+
+ /*
+ * All 44x variants deal with cache management differently
+ * because they have the address translation always enabled.
+ * The 40x ppc's don't use address translation in U-Boot at all,
+ * so we have to distinguish here between 40x and 44x.
+ */
+#ifdef CONFIG_440
+/* void cache_post_disable (int tlb)
+ */
+cache_post_disable:
+ tlbre r0, r3, 0x0002
+ ori r0, r0, TLB_WORD2_I_ENABLE@l
+ tlbwe r0, r3, 0x0002
+ sync
+ isync
+ blr
+
+/* void cache_post_wt (int tlb)
+ */
+cache_post_wt:
+ tlbre r0, r3, 0x0002
+ ori r0, r0, TLB_WORD2_W_ENABLE@l
+ andi. r0, r0, ~TLB_WORD2_I_ENABLE@l
+ tlbwe r0, r3, 0x0002
+ sync
+ isync
+ blr
+
+/* void cache_post_wb (int tlb)
+ */
+cache_post_wb:
+ tlbre r0, r3, 0x0002
+ andi. r0, r0, ~TLB_WORD2_W_ENABLE@l
+ andi. r0, r0, ~TLB_WORD2_I_ENABLE@l
+ tlbwe r0, r3, 0x0002
+ sync
+ isync
+ blr
+#else
+/* void cache_post_disable (int tlb)
+ */
+cache_post_disable:
+ lis r0, 0x0000
+ ori r0, r0, 0x0000
+ mtdccr r0
+ sync
+ isync
+ blr
+
+/* void cache_post_wt (int tlb)
+ */
+cache_post_wt:
+ lis r0, 0x8000
+ ori r0, r0, 0x0000
+ mtdccr r0
+ lis r0, 0x8000
+ ori r0, r0, 0x0000
+ mtdcwr r0
+ sync
+ isync
+ blr
+
+/* void cache_post_wb (int tlb)
+ */
+cache_post_wb:
+ lis r0, 0x8000
+ ori r0, r0, 0x0000
+ mtdccr r0
+ lis r0, 0x0000
+ ori r0, r0, 0x0000
+ mtdcwr r0
+ sync
+ isync
+ blr
+#endif
+
+/* void cache_post_dinvalidate (void *p, int size)
+ */
+cache_post_dinvalidate:
+ dcbi r0, r3
+ addi r3, r3, CFG_CACHELINE_SIZE
+ subic. r4, r4, CFG_CACHELINE_SIZE
+ bgt cache_post_dinvalidate
+ sync
+ blr
+
+/* void cache_post_dstore (void *p, int size)
+ */
+cache_post_dstore:
+ dcbst r0, r3
+ addi r3, r3, CFG_CACHELINE_SIZE
+ subic. r4, r4, CFG_CACHELINE_SIZE
+ bgt cache_post_dstore
+ sync
+ blr
+
+/* void cache_post_dtouch (void *p, int size)
+ */
+cache_post_dtouch:
+ dcbt r0, r3
+ addi r3, r3, CFG_CACHELINE_SIZE
+ subic. r4, r4, CFG_CACHELINE_SIZE
+ bgt cache_post_dtouch
+ sync
+ blr
+
+/* void cache_post_iinvalidate (void)
+ */
+cache_post_iinvalidate:
+ iccci r0, r0
+ sync
+ blr
+
+/* void cache_post_memset (void *p, int val, int size)
+ */
+cache_post_memset:
+ mtctr r5
+1:
+ stb r4, 0(r3)
+ addi r3, r3, 1
+ bdnz 1b
+ blr
+
+/* int cache_post_check (void *p, int size)
+ */
+cache_post_check:
+ mtctr r4
+1:
+ lbz r0, 0(r3)
+ addi r3, r3, 1
+ cmpwi r0, 0xff
+ bne 2f
+ bdnz 1b
+ li r3, 0
+ blr
+2:
+ li r3, -1
+ blr
+
+#define CACHE_POST_DISABLE() \
+ mr r3, r10; \
+ bl cache_post_disable
+
+#define CACHE_POST_WT() \
+ mr r3, r10; \
+ bl cache_post_wt
+
+#define CACHE_POST_WB() \
+ mr r3, r10; \
+ bl cache_post_wb
+
+#define CACHE_POST_DINVALIDATE() \
+ mr r3, r11; \
+ mr r4, r12; \
+ bl cache_post_dinvalidate
+
+#define CACHE_POST_DFLUSH() \
+ mr r3, r11; \
+ mr r4, r12; \
+ bl cache_post_dflush
+
+#define CACHE_POST_DSTORE() \
+ mr r3, r11; \
+ mr r4, r12; \
+ bl cache_post_dstore
+
+#define CACHE_POST_DTOUCH() \
+ mr r3, r11; \
+ mr r4, r12; \
+ bl cache_post_dtouch
+
+#define CACHE_POST_IINVALIDATE() \
+ bl cache_post_iinvalidate
+
+#define CACHE_POST_MEMSET(val) \
+ mr r3, r11; \
+ li r4, val; \
+ mr r5, r12; \
+ bl cache_post_memset
+
+#define CACHE_POST_CHECK() \
+ mr r3, r11; \
+ mr r4, r12; \
+ bl cache_post_check; \
+ mr r13, r3
+
+/*
+ * Write and read 0xff pattern with caching enabled.
+ */
+ .global cache_post_test1
+cache_post_test1:
+ mflr r9
+ mr r10, r3 /* tlb */
+ mr r11, r4 /* p */
+ mr r12, r5 /* size */
+
+ CACHE_POST_WB()
+ CACHE_POST_DINVALIDATE()
+
+ /* Write the negative pattern to the test area */
+ CACHE_POST_MEMSET(0xff)
+
+ /* Read the test area */
+ CACHE_POST_CHECK()
+
+ CACHE_POST_DINVALIDATE()
+ CACHE_POST_DISABLE()
+
+ mr r3, r13
+ mtlr r9
+ blr
+
+/*
+ * Write zeroes with caching enabled.
+ * Write 0xff pattern with caching disabled.
+ * Read 0xff pattern with caching enabled.
+ */
+ .global cache_post_test2
+cache_post_test2:
+ mflr r9
+ mr r10, r3 /* tlb */
+ mr r11, r4 /* p */
+ mr r12, r5 /* size */
+
+ CACHE_POST_WB()
+ CACHE_POST_DINVALIDATE()
+
+ /* Write the zero pattern to the test area */
+ CACHE_POST_MEMSET(0)
+
+ CACHE_POST_DINVALIDATE()
+ CACHE_POST_DISABLE()
+
+ /* Write the negative pattern to the test area */
+ CACHE_POST_MEMSET(0xff)
+
+ CACHE_POST_WB()
+
+ /* Read the test area */
+ CACHE_POST_CHECK()
+
+ CACHE_POST_DINVALIDATE()
+ CACHE_POST_DISABLE()
+
+ mr r3, r13
+ mtlr r9
+ blr
+
+/*
+ * Write-through mode test.
+ * Write zeroes, store the cache, write 0xff pattern.
+ * Invalidate the cache.
+ * Check that 0xff pattern is read.
+ */
+ .global cache_post_test3
+cache_post_test3:
+ mflr r9
+ mr r10, r3 /* tlb */
+ mr r11, r4 /* p */
+ mr r12, r5 /* size */
+
+ CACHE_POST_WT()
+ CACHE_POST_DINVALIDATE()
+
+ /* Cache the test area */
+ CACHE_POST_DTOUCH()
+
+ /* Write the zero pattern to the test area */
+ CACHE_POST_MEMSET(0)
+
+ CACHE_POST_DSTORE()
+
+ /* Write the negative pattern to the test area */
+ CACHE_POST_MEMSET(0xff)
+
+ CACHE_POST_DINVALIDATE()
+ CACHE_POST_DISABLE()
+
+ /* Read the test area */
+ CACHE_POST_CHECK()
+
+ mr r3, r13
+ mtlr r9
+ blr
+
+/*
+ * Write-back mode test.
+ * Write 0xff pattern, store the cache, write zeroes.
+ * Invalidate the cache.
+ * Check that 0xff pattern is read.
+ */
+ .global cache_post_test4
+cache_post_test4:
+ mflr r9
+ mr r10, r3 /* tlb */
+ mr r11, r4 /* p */
+ mr r12, r5 /* size */
+
+ CACHE_POST_WB()
+ CACHE_POST_DINVALIDATE()
+
+ /* Cache the test area */
+ CACHE_POST_DTOUCH()
+
+ /* Write the negative pattern to the test area */
+ CACHE_POST_MEMSET(0xff)
+
+ CACHE_POST_DSTORE()
+
+ /* Write the zero pattern to the test area */
+ CACHE_POST_MEMSET(0)
+
+ CACHE_POST_DINVALIDATE()
+ CACHE_POST_DISABLE()
+
+ /* Read the test area */
+ CACHE_POST_CHECK()
+
+ mr r3, r13
+ mtlr r9
+ blr
+
+/*
+ * Load the test instructions into the instruction cache.
+ * Replace the test instructions.
+ * Check that the original instructions are executed.
+ */
+ .global cache_post_test5
+cache_post_test5:
+ mflr r9
+ mr r10, r3 /* tlb */
+ mr r11, r4 /* p */
+ mr r12, r5 /* size */
+
+ CACHE_POST_WT()
+ CACHE_POST_IINVALIDATE()
+
+ /* Compute r13 = cache_post_test_inst */
+ bl cache_post_test5_reloc
+cache_post_test5_reloc:
+ mflr r13
+ lis r0, (cache_post_test_inst - cache_post_test5_reloc)@h
+ ori r0, r0, (cache_post_test_inst - cache_post_test5_reloc)@l
+ add r13, r13, r0
+
+ /* Copy the test instructions to the test area */
+ lwz r0, 0(r13)
+ stw r0, 0(r11)
+ lwz r0, 8(r13)
+ stw r0, 4(r11)
+ sync
+
+ /* Invalidate the cache line */
+ icbi r0, r11
+ sync
+ isync
+
+ /* Execute the test instructions */
+ mtlr r11
+ blrl
+
+ /* Replace the test instruction */
+ lwz r0, 4(r13)
+ stw r0, 0(r11)
+ sync
+
+ /* Do not invalidate the cache line */
+ isync
+
+ /* Execute the test instructions */
+ mtlr r11
+ blrl
+ mr r13, r3
+
+ CACHE_POST_IINVALIDATE()
+ CACHE_POST_DINVALIDATE()
+ CACHE_POST_DISABLE()
+
+ mr r3, r13
+ mtlr r9
+ blr
+
+/*
+ * Load the test instructions into the instruction cache.
+ * Replace the test instructions and invalidate the cache.
+ * Check that the replaced instructions are executed.
+ */
+ .global cache_post_test6
+cache_post_test6:
+ mflr r9
+ mr r10, r3 /* tlb */
+ mr r11, r4 /* p */
+ mr r12, r5 /* size */
+
+ CACHE_POST_WT()
+ CACHE_POST_IINVALIDATE()
+
+ /* Compute r13 = cache_post_test_inst */
+ bl cache_post_test6_reloc
+cache_post_test6_reloc:
+ mflr r13
+ lis r0, (cache_post_test_inst - cache_post_test6_reloc)@h
+ ori r0, r0, (cache_post_test_inst - cache_post_test6_reloc)@l
+ add r13, r13, r0
+
+ /* Copy the test instructions to the test area */
+ lwz r0, 4(r13)
+ stw r0, 0(r11)
+ lwz r0, 8(r13)
+ stw r0, 4(r11)
+ sync
+
+ /* Invalidate the cache line */
+ icbi r0, r11
+ sync
+ isync
+
+ /* Execute the test instructions */
+ mtlr r11
+ blrl
+
+ /* Replace the test instruction */
+ lwz r0, 0(r13)
+ stw r0, 0(r11)
+ sync
+
+ /* Invalidate the cache line */
+ icbi r0, r11
+ sync
+ isync
+
+ /* Execute the test instructions */
+ mtlr r11
+ blrl
+ mr r13, r3
+
+ CACHE_POST_IINVALIDATE()
+ CACHE_POST_DINVALIDATE()
+ CACHE_POST_DISABLE()
+
+ mr r3, r13
+ mtlr r9
+ blr
+
+/* Test instructions.
+ */
+cache_post_test_inst:
+ li r3, 0
+ li r3, -1
+ blr
+
+#endif /* CONFIG_POST & CFG_POST_CACHE */
+#endif /* CONFIG_POST */
diff --git a/post/cpu/ppc4xx/ether.c b/post/cpu/ppc4xx/ether.c
new file mode 100644
index 0000000..ab23ca5
--- /dev/null
+++ b/post/cpu/ppc4xx/ether.c
@@ -0,0 +1,402 @@
+/*
+ * (C) Copyright 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Author: Igor Lisitsin <igor@emcraft.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+/*
+ * Ethernet test
+ *
+ * The Ethernet Media Access Controllers (EMAC) are tested in the
+ * internal loopback mode.
+ * The controllers are configured accordingly and several packets
+ * are transmitted. The configurable test parameters are:
+ * MIN_PACKET_LENGTH - minimum size of packet to transmit
+ * MAX_PACKET_LENGTH - maximum size of packet to transmit
+ * TEST_NUM - number of tests
+ */
+
+#ifdef CONFIG_POST
+
+#include <post.h>
+
+#if CONFIG_POST & CFG_POST_ETHER
+
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <405_mal.h>
+#include <ppc4xx_enet.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_440SPE) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+#define SDR0_MFR_ETH_CLK_SEL_V(n) ((0x01<<27) / (n+1))
+#endif
+
+#define MIN_PACKET_LENGTH 64
+#define MAX_PACKET_LENGTH 256
+#define TEST_NUM 1
+
+static volatile mal_desc_t tx __cacheline_aligned;
+static volatile mal_desc_t rx __cacheline_aligned;
+static char *tx_buf;
+static char *rx_buf;
+
+static void ether_post_init (int devnum, int hw_addr)
+{
+ int i;
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+ unsigned mode_reg;
+ sys_info_t sysinfo;
+#endif
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || defined(CONFIG_440SPE)
+ unsigned long mfr;
+#endif
+
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+ /* Need to get the OPB frequency so we can access the PHY */
+ get_sys_info (&sysinfo);
+#endif
+
+#if defined(CONFIG_440SPE) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+ /* provide clocks for EMAC internal loopback */
+ mfsdr (sdr_mfr, mfr);
+ mfr |= SDR0_MFR_ETH_CLK_SEL_V(devnum);
+ mtsdr (sdr_mfr, mfr);
+ sync ();
+#endif
+ /* reset emac */
+ out32 (EMAC_M0 + hw_addr, EMAC_M0_SRST);
+ sync ();
+
+ for (i = 0;; i++) {
+ if (!(in32 (EMAC_M0 + hw_addr) & EMAC_M0_SRST))
+ break;
+ if (i >= 1000) {
+ printf ("Timeout resetting EMAC\n");
+ break;
+ }
+ udelay (1000);
+ }
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+ /* Whack the M1 register */
+ mode_reg = 0x0;
+ if (sysinfo.freqOPB <= 50000000);
+ else if (sysinfo.freqOPB <= 66666667)
+ mode_reg |= EMAC_M1_OBCI_66;
+ else if (sysinfo.freqOPB <= 83333333)
+ mode_reg |= EMAC_M1_OBCI_83;
+ else if (sysinfo.freqOPB <= 100000000)
+ mode_reg |= EMAC_M1_OBCI_100;
+ else
+ mode_reg |= EMAC_M1_OBCI_GT100;
+
+ out32 (EMAC_M1 + hw_addr, mode_reg);
+
+#endif /* defined(CONFIG_440GX) || defined(CONFIG_440SP) */
+
+ /* set the Mal configuration reg */
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+ mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA |
+ MAL_CR_PLBLT_DEFAULT | 0x00330000);
+#else
+ mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);
+ /* Errata 1.12: MAL_1 -- Disable MAL bursting */
+ if (get_pvr() == PVR_440GP_RB) {
+ mtdcr (malmcr, mfdcr(malmcr) & ~MAL_CR_PLBB);
+ }
+#endif
+ /* setup buffer descriptors */
+ tx.ctrl = MAL_TX_CTRL_WRAP;
+ tx.data_len = 0;
+ tx.data_ptr = (char*)L1_CACHE_ALIGN((u32)tx_buf);
+
+ rx.ctrl = MAL_TX_CTRL_WRAP | MAL_RX_CTRL_EMPTY;
+ rx.data_len = 0;
+ rx.data_ptr = (char*)L1_CACHE_ALIGN((u32)rx_buf);
+
+ switch (devnum) {
+ case 1:
+ /* setup MAL tx & rx channel pointers */
+#if defined (CONFIG_405EP) || defined (CONFIG_440EP) || defined (CONFIG_440GR)
+ mtdcr (maltxctp2r, &tx);
+#else
+ mtdcr (maltxctp1r, &tx);
+#endif
+#if defined(CONFIG_440)
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (malrxbattr, 0x0);
+#endif
+ mtdcr (malrxctp1r, &rx);
+ /* set RX buffer size */
+ mtdcr (malrcbs1, PKTSIZE_ALIGN / 16);
+ break;
+ case 0:
+ default:
+ /* setup MAL tx & rx channel pointers */
+#if defined(CONFIG_440)
+ mtdcr (maltxbattr, 0x0);
+ mtdcr (malrxbattr, 0x0);
+#endif
+ mtdcr (maltxctp0r, &tx);
+ mtdcr (malrxctp0r, &rx);
+ /* set RX buffer size */
+ mtdcr (malrcbs0, PKTSIZE_ALIGN / 16);
+ break;
+ }
+
+ /* Enable MAL transmit and receive channels */
+#if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ mtdcr (maltxcasr, (MAL_TXRX_CASR >> (devnum*2)));
+#else
+ mtdcr (maltxcasr, (MAL_TXRX_CASR >> devnum));
+#endif
+ mtdcr (malrxcasr, (MAL_TXRX_CASR >> devnum));
+
+ /* set internal loopback mode */
+#ifdef CFG_POST_ETHER_EXT_LOOPBACK
+ out32 (EMAC_M1 + hw_addr, EMAC_M1_FDE | 0 |
+ EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K |
+ EMAC_M1_MF_100MBPS | EMAC_M1_IST |
+ in32 (EMAC_M1));
+#else
+ out32 (EMAC_M1 + hw_addr, EMAC_M1_FDE | EMAC_M1_ILE |
+ EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K |
+ EMAC_M1_MF_100MBPS | EMAC_M1_IST |
+ in32 (EMAC_M1));
+#endif
+
+ /* set transmit enable & receive enable */
+ out32 (EMAC_M0 + hw_addr, EMAC_M0_TXE | EMAC_M0_RXE);
+
+ /* enable broadcast address */
+ out32 (EMAC_RXM + hw_addr, EMAC_RMR_BAE);
+
+ /* set transmit request threshold register */
+ out32 (EMAC_TRTR + hw_addr, 0x18000000); /* 256 byte threshold */
+
+ /* set receive low/high water mark register */
+#if defined(CONFIG_440)
+ /* 440s has a 64 byte burst length */
+ out32 (EMAC_RX_HI_LO_WMARK + hw_addr, 0x80009000);
+#else
+ /* 405s have a 16 byte burst length */
+ out32 (EMAC_RX_HI_LO_WMARK + hw_addr, 0x0f002000);
+#endif /* defined(CONFIG_440) */
+ out32 (EMAC_TXM1 + hw_addr, 0xf8640000);
+
+ /* Set fifo limit entry in tx mode 0 */
+ out32 (EMAC_TXM0 + hw_addr, 0x00000003);
+ /* Frame gap set */
+ out32 (EMAC_I_FRAME_GAP_REG + hw_addr, 0x00000008);
+ sync ();
+}
+
+static void ether_post_halt (int devnum, int hw_addr)
+{
+ int i = 0;
+#if defined(CONFIG_440SPE) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+ unsigned long mfr;
+#endif
+
+ /* 1st reset MAL channel */
+ /* Note: writing a 0 to a channel has no effect */
+#if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ mtdcr (maltxcarr, MAL_TXRX_CASR >> (devnum * 2));
+#else
+ mtdcr (maltxcarr, MAL_TXRX_CASR >> devnum);
+#endif
+ mtdcr (malrxcarr, MAL_TXRX_CASR >> devnum);
+
+ /* wait for reset */
+ while (mfdcr (malrxcasr) & (MAL_TXRX_CASR >> devnum)) {
+ if (i++ >= 1000)
+ break;
+ udelay (1000);
+ }
+ /* emac reset */
+ out32 (EMAC_M0 + hw_addr, EMAC_M0_SRST);
+
+#if defined(CONFIG_440SPE) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+ /* remove clocks for EMAC internal loopback */
+ mfsdr (sdr_mfr, mfr);
+ mfr &= ~SDR0_MFR_ETH_CLK_SEL_V(devnum);
+ mtsdr (sdr_mfr, mfr);
+#endif
+}
+
+static void ether_post_send (int devnum, int hw_addr, void *packet, int length)
+{
+ int i = 0;
+
+ while (tx.ctrl & MAL_TX_CTRL_READY) {
+ if (i++ > 100) {
+ printf ("TX timeout\n");
+ return;
+ }
+ udelay (1000);
+ }
+ tx.ctrl = MAL_TX_CTRL_READY | MAL_TX_CTRL_WRAP | MAL_TX_CTRL_LAST |
+ EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP;
+ tx.data_len = length;
+ memcpy (tx.data_ptr, packet, length);
+ sync ();
+
+ out32 (EMAC_TXM0 + hw_addr, in32 (EMAC_TXM0 + hw_addr) | EMAC_TXM0_GNP0);
+ sync ();
+}
+
+static int ether_post_recv (int devnum, int hw_addr, void *packet, int max_length)
+{
+ int length;
+ int i = 0;
+
+ while (rx.ctrl & MAL_RX_CTRL_EMPTY) {
+ if (i++ > 100) {
+ printf ("RX timeout\n");
+ return 0;
+ }
+ udelay (1000);
+ }
+ length = rx.data_len - 4;
+ if (length <= max_length)
+ memcpy(packet, rx.data_ptr, length);
+ sync ();
+
+ rx.ctrl |= MAL_RX_CTRL_EMPTY;
+ sync ();
+
+ return length;
+}
+
+ /*
+ * Test routines
+ */
+
+static void packet_fill (char *packet, int length)
+{
+ char c = (char) length;
+ int i;
+
+ /* set up ethernet header */
+ memset (packet, 0xff, 14);
+
+ for (i = 14; i < length; i++) {
+ packet[i] = c++;
+ }
+}
+
+static int packet_check (char *packet, int length)
+{
+ char c = (char) length;
+ int i;
+
+ for (i = 14; i < length; i++) {
+ if (packet[i] != c++)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int test_ctlr (int devnum, int hw_addr)
+{
+ int res = -1;
+ char packet_send[MAX_PACKET_LENGTH];
+ char packet_recv[MAX_PACKET_LENGTH];
+ int length;
+ int i;
+ int l;
+
+ ether_post_init (devnum, hw_addr);
+
+ for (i = 0; i < TEST_NUM; i++) {
+ for (l = MIN_PACKET_LENGTH; l <= MAX_PACKET_LENGTH; l++) {
+ packet_fill (packet_send, l);
+
+ ether_post_send (devnum, hw_addr, packet_send, l);
+
+ length = ether_post_recv (devnum, hw_addr, packet_recv,
+ sizeof (packet_recv));
+
+ if (length != l || packet_check (packet_recv, length) < 0) {
+ goto Done;
+ }
+ }
+ }
+
+ res = 0;
+
+Done:
+
+ ether_post_halt (devnum, hw_addr);
+
+ if (res != 0) {
+ post_log ("EMAC%d test failed\n", devnum);
+ }
+
+ return res;
+}
+
+int ether_post_test (int flags)
+{
+ int res = 0;
+
+ /* Allocate tx & rx packet buffers */
+ tx_buf = malloc (PKTSIZE_ALIGN + CFG_CACHELINE_SIZE);
+ rx_buf = malloc (PKTSIZE_ALIGN + CFG_CACHELINE_SIZE);
+
+ if (!tx_buf || !rx_buf) {
+ printf ("Failed to allocate packet buffers\n");
+ res = -1;
+ goto out_free;
+ }
+
+ /* EMAC0 */
+ if (test_ctlr (0, 0))
+ res = -1;
+
+ /* EMAC1 */
+ if (test_ctlr (1, 0x100))
+ res = -1;
+
+out_free:
+ free (tx_buf);
+ free (rx_buf);
+
+ return res;
+}
+
+#endif /* CONFIG_POST & CFG_POST_ETHER */
+#endif /* CONFIG_POST */
diff --git a/post/cpu/ppc4xx/fpu.c b/post/cpu/ppc4xx/fpu.c
new file mode 100644
index 0000000..0c26fe0
--- /dev/null
+++ b/post/cpu/ppc4xx/fpu.c
@@ -0,0 +1,59 @@
+/*
+ * (C) Copyright 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Author: Sergei Poselenov <sposelenov@emcraft.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+
+#ifdef CONFIG_POST
+#if defined(CONFIG_440EP) || \
+ defined(CONFIG_440EPX)
+
+#include <asm/processor.h>
+#include <ppc4xx.h>
+
+
+int fpu_status(void)
+{
+ if (mfspr(ccr0) & CCR0_DAPUIB)
+ return 0; /* Disabled */
+ else
+ return 1; /* Enabled */
+}
+
+
+void fpu_disable(void)
+{
+ mtspr(ccr0, mfspr(ccr0) | CCR0_DAPUIB);
+ mtmsr(mfmsr() & ~MSR_FP);
+}
+
+
+void fpu_enable(void)
+{
+ mtspr(ccr0, mfspr(ccr0) & ~CCR0_DAPUIB);
+ mtmsr(mfmsr() | MSR_FP);
+}
+
+#endif
+#endif /* CONFIG_POST */
diff --git a/post/cpu/ppc4xx/spr.c b/post/cpu/ppc4xx/spr.c
new file mode 100644
index 0000000..3e74634
--- /dev/null
+++ b/post/cpu/ppc4xx/spr.c
@@ -0,0 +1,182 @@
+/*
+ * (C) Copyright 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Author: Igor Lisitsin <igor@emcraft.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+/*
+ * SPR test
+ *
+ * The test checks the contents of Special Purpose Registers (SPR) listed
+ * in the spr_test_list array below.
+ * Each SPR value is read using mfspr instruction, some bits are masked
+ * according to the table and the resulting value is compared to the
+ * corresponding table value.
+ */
+
+#ifdef CONFIG_POST
+
+#include <post.h>
+
+#if CONFIG_POST & CFG_POST_SPR
+
+#include <asm/processor.h>
+
+static struct {
+ int number;
+ char * name;
+ unsigned long mask;
+ unsigned long value;
+} spr_test_list [] = {
+ /* Standard Special-Purpose Registers */
+
+ {0x001, "XER", 0x00000000, 0x00000000},
+ {0x008, "LR", 0x00000000, 0x00000000},
+ {0x009, "CTR", 0x00000000, 0x00000000},
+ {0x016, "DEC", 0x00000000, 0x00000000},
+ {0x01a, "SRR0", 0x00000000, 0x00000000},
+ {0x01b, "SRR1", 0x00000000, 0x00000000},
+ {0x110, "SPRG0", 0x00000000, 0x00000000},
+ {0x111, "SPRG1", 0x00000000, 0x00000000},
+ {0x112, "SPRG2", 0x00000000, 0x00000000},
+ {0x113, "SPRG3", 0x00000000, 0x00000000},
+ {0x11f, "PVR", 0x00000000, 0x00000000},
+
+ /* Additional Special-Purpose Registers.
+ * The values must match the initialization
+ * values from cpu/ppc4xx/start.S
+ */
+ {0x30, "PID", 0x00000000, 0x00000000},
+ {0x3a, "CSRR0", 0x00000000, 0x00000000},
+ {0x3b, "CSRR1", 0x00000000, 0x00000000},
+ {0x3d, "DEAR", 0x00000000, 0x00000000},
+ {0x3e, "ESR", 0x00000000, 0x00000000},
+ {0x3f, "IVPR", 0xffff0000, 0x00000000},
+ {0x100, "USPRG0", 0x00000000, 0x00000000},
+ {0x104, "SPRG4", 0x00000000, 0x00000000},
+ {0x105, "SPRG5", 0x00000000, 0x00000000},
+ {0x106, "SPRG6", 0x00000000, 0x00000000},
+ {0x107, "SPRG7", 0x00000000, 0x00000000},
+ {0x10c, "TBL", 0x00000000, 0x00000000},
+ {0x10d, "TBU", 0x00000000, 0x00000000},
+ {0x11e, "PIR", 0x0000000f, 0x00000000},
+ {0x130, "DBSR", 0x00000000, 0x00000000},
+ {0x134, "DBCR0", 0x00000000, 0x00000000},
+ {0x135, "DBCR1", 0x00000000, 0x00000000},
+ {0x136, "DBCR2", 0x00000000, 0x00000000},
+ {0x138, "IAC1", 0x00000000, 0x00000000},
+ {0x139, "IAC2", 0x00000000, 0x00000000},
+ {0x13a, "IAC3", 0x00000000, 0x00000000},
+ {0x13b, "IAC4", 0x00000000, 0x00000000},
+ {0x13c, "DAC1", 0x00000000, 0x00000000},
+ {0x13d, "DAC2", 0x00000000, 0x00000000},
+ {0x13e, "DVC1", 0x00000000, 0x00000000},
+ {0x13f, "DVC2", 0x00000000, 0x00000000},
+ {0x150, "TSR", 0x00000000, 0x00000000},
+ {0x154, "TCR", 0x00000000, 0x00000000},
+ {0x190, "IVOR0", 0x0000fff0, 0x00000100},
+ {0x191, "IVOR1", 0x0000fff0, 0x00000200},
+ {0x192, "IVOR2", 0x0000fff0, 0x00000300},
+ {0x193, "IVOR3", 0x0000fff0, 0x00000400},
+ {0x194, "IVOR4", 0x0000fff0, 0x00000500},
+ {0x195, "IVOR5", 0x0000fff0, 0x00000600},
+ {0x196, "IVOR6", 0x0000fff0, 0x00000700},
+ {0x197, "IVOR7", 0x0000fff0, 0x00000800},
+ {0x198, "IVOR8", 0x0000fff0, 0x00000c00},
+ {0x199, "IVOR9", 0x00000000, 0x00000000},
+ {0x19a, "IVOR10", 0x0000fff0, 0x00000900},
+ {0x19b, "IVOR11", 0x00000000, 0x00000000},
+ {0x19c, "IVOR12", 0x00000000, 0x00000000},
+ {0x19d, "IVOR13", 0x0000fff0, 0x00001300},
+ {0x19e, "IVOR14", 0x0000fff0, 0x00001400},
+ {0x19f, "IVOR15", 0x0000fff0, 0x00002000},
+ {0x23a, "MCSRR0", 0x00000000, 0x00000000},
+ {0x23b, "MCSRR1", 0x00000000, 0x00000000},
+ {0x23c, "MCSR", 0x00000000, 0x00000000},
+ {0x370, "INV0", 0x00000000, 0x00000000},
+ {0x371, "INV1", 0x00000000, 0x00000000},
+ {0x372, "INV2", 0x00000000, 0x00000000},
+ {0x373, "INV3", 0x00000000, 0x00000000},
+ {0x374, "ITV0", 0x00000000, 0x00000000},
+ {0x375, "ITV1", 0x00000000, 0x00000000},
+ {0x376, "ITV2", 0x00000000, 0x00000000},
+ {0x377, "ITV3", 0x00000000, 0x00000000},
+ {0x378, "CCR1", 0x00000000, 0x00000000},
+ {0x390, "DNV0", 0x00000000, 0x00000000},
+ {0x391, "DNV1", 0x00000000, 0x00000000},
+ {0x392, "DNV2", 0x00000000, 0x00000000},
+ {0x393, "DNV3", 0x00000000, 0x00000000},
+ {0x394, "DTV0", 0x00000000, 0x00000000},
+ {0x395, "DTV1", 0x00000000, 0x00000000},
+ {0x396, "DTV2", 0x00000000, 0x00000000},
+ {0x397, "DTV3", 0x00000000, 0x00000000},
+ {0x398, "DVLIM", 0x0fc1f83f, 0x0001f800},
+ {0x399, "IVLIM", 0x0fc1f83f, 0x0001f800},
+ {0x39b, "RSTCFG", 0x00000000, 0x00000000},
+ {0x39c, "DCDBTRL", 0x00000000, 0x00000000},
+ {0x39d, "DCDBTRH", 0x00000000, 0x00000000},
+ {0x39e, "ICDBTRL", 0x00000000, 0x00000000},
+ {0x39f, "ICDBTRH", 0x00000000, 0x00000000},
+ {0x3b2, "MMUCR", 0x00000000, 0x00000000},
+ {0x3b3, "CCR0", 0x00000000, 0x00000000},
+ {0x3d3, "ICDBDR", 0x00000000, 0x00000000},
+ {0x3f3, "DBDR", 0x00000000, 0x00000000},
+};
+
+static int spr_test_list_size =
+ sizeof (spr_test_list) / sizeof (spr_test_list[0]);
+
+int spr_post_test (int flags)
+{
+ int ret = 0;
+ int i;
+
+ unsigned long code[] = {
+ 0x7c6002a6, /* mfspr r3,SPR */
+ 0x4e800020 /* blr */
+ };
+ unsigned long (*get_spr) (void) = (void *) code;
+
+ for (i = 0; i < spr_test_list_size; i++) {
+ int num = spr_test_list[i].number;
+
+ /* mfspr r3,num */
+ code[0] = 0x7c6002a6 | ((num & 0x1F) << 16) | ((num & 0x3E0) << 6);
+
+ asm volatile ("isync");
+
+ if ((get_spr () & spr_test_list[i].mask) !=
+ (spr_test_list[i].value & spr_test_list[i].mask)) {
+ post_log ("The value of %s special register "
+ "is incorrect: 0x%08X\n",
+ spr_test_list[i].name, get_spr ());
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_POST & CFG_POST_SPR */
+#endif /* CONFIG_POST */
diff --git a/post/cpu/ppc4xx/uart.c b/post/cpu/ppc4xx/uart.c
new file mode 100644
index 0000000..7c3ed40
--- /dev/null
+++ b/post/cpu/ppc4xx/uart.c
@@ -0,0 +1,381 @@
+/*
+ * (C) Copyright 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Author: Igor Lisitsin <igor@emcraft.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+/*
+ * UART test
+ *
+ * The controllers are configured to loopback mode and several
+ * characters are transmitted.
+ */
+
+#ifdef CONFIG_POST
+
+#include <post.h>
+
+#if CONFIG_POST & CFG_POST_UART
+
+/*
+ * This table defines the UART's that should be tested and can
+ * be overridden in the board config file
+ */
+#ifndef CFG_POST_UART_TABLE
+#define CFG_POST_UART_TABLE {UART0_BASE, UART1_BASE, UART2_BASE, UART3_BASE}
+#endif
+
+#include <asm/processor.h>
+#include <serial.h>
+
+#if defined(CONFIG_440)
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+#define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000300
+#define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000400
+#define UART2_BASE CFG_PERIPHERAL_BASE + 0x00000500
+#define UART3_BASE CFG_PERIPHERAL_BASE + 0x00000600
+#else
+#define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000200
+#define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000300
+#endif
+
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+#define UART2_BASE CFG_PERIPHERAL_BASE + 0x00000600
+#endif
+
+#if defined(CONFIG_440GP)
+#define CR0_MASK 0x3fff0000
+#define CR0_EXTCLK_ENA 0x00600000
+#define CR0_UDIV_POS 16
+#define UDIV_SUBTRACT 1
+#define UART0_SDR cntrl0
+#define MFREG(a, d) d = mfdcr(a)
+#define MTREG(a, d) mtdcr(a, d)
+#else /* #if defined(CONFIG_440GP) */
+/* all other 440 PPC's access clock divider via sdr register */
+#define CR0_MASK 0xdfffffff
+#define CR0_EXTCLK_ENA 0x00800000
+#define CR0_UDIV_POS 0
+#define UDIV_SUBTRACT 0
+#define UART0_SDR sdr_uart0
+#define UART1_SDR sdr_uart1
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPx) || \
+ defined(CONFIG_440GR) || defined(CONFIG_440GRx) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPe)
+#define UART2_SDR sdr_uart2
+#endif
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPx) || \
+ defined(CONFIG_440GR) || defined(CONFIG_440GRx)
+#define UART3_SDR sdr_uart3
+#endif
+#define MFREG(a, d) mfsdr(a, d)
+#define MTREG(a, d) mtsdr(a, d)
+#endif /* #if defined(CONFIG_440GP) */
+#elif defined(CONFIG_405EP) || defined(CONFIG_405EZ)
+#define UART0_BASE 0xef600300
+#define UART1_BASE 0xef600400
+#define UCR0_MASK 0x0000007f
+#define UCR1_MASK 0x00007f00
+#define UCR0_UDIV_POS 0
+#define UCR1_UDIV_POS 8
+#define UDIV_MAX 127
+#else /* CONFIG_405GP || CONFIG_405CR */
+#define UART0_BASE 0xef600300
+#define UART1_BASE 0xef600400
+#define CR0_MASK 0x00001fff
+#define CR0_EXTCLK_ENA 0x000000c0
+#define CR0_UDIV_POS 1
+#define UDIV_MAX 32
+#endif
+
+#define UART_RBR 0x00
+#define UART_THR 0x00
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_LSR 0x05
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/*
+ * Line Status Register.
+ */
+#define asyncLSRDataReady1 0x01
+#define asyncLSROverrunError1 0x02
+#define asyncLSRParityError1 0x04
+#define asyncLSRFramingError1 0x08
+#define asyncLSRBreakInterrupt1 0x10
+#define asyncLSRTxHoldEmpty1 0x20
+#define asyncLSRTxShiftEmpty1 0x40
+#define asyncLSRRxFifoError1 0x80
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_440)
+#if !defined(CFG_EXT_SERIAL_CLOCK)
+static void serial_divs (int baudrate, unsigned long *pudiv,
+ unsigned short *pbdiv)
+{
+ sys_info_t sysinfo;
+ unsigned long div; /* total divisor udiv * bdiv */
+ unsigned long umin; /* minimum udiv */
+ unsigned short diff; /* smallest diff */
+ unsigned long udiv; /* best udiv */
+ unsigned short idiff; /* current diff */
+ unsigned short ibdiv; /* current bdiv */
+ unsigned long i;
+ unsigned long est; /* current estimate */
+
+ get_sys_info(&sysinfo);
+
+ udiv = 32; /* Assume lowest possible serial clk */
+ div = sysinfo.freqPLB / (16 * baudrate); /* total divisor */
+ umin = sysinfo.pllOpbDiv << 1; /* 2 x OPB divisor */
+ diff = 32; /* highest possible */
+
+ /* i is the test udiv value -- start with the largest
+ * possible (32) to minimize serial clock and constrain
+ * search to umin.
+ */
+ for (i = 32; i > umin; i--) {
+ ibdiv = div / i;
+ est = i * ibdiv;
+ idiff = (est > div) ? (est-div) : (div-est);
+ if (idiff == 0) {
+ udiv = i;
+ break; /* can't do better */
+ } else if (idiff < diff) {
+ udiv = i; /* best so far */
+ diff = idiff; /* update lowest diff*/
+ }
+ }
+
+ *pudiv = udiv;
+ *pbdiv = div / udiv;
+}
+#endif
+
+static int uart_post_init (unsigned long dev_base)
+{
+ unsigned long reg;
+ unsigned long udiv;
+ unsigned short bdiv;
+ volatile char val;
+#ifdef CFG_EXT_SERIAL_CLOCK
+ unsigned long tmp;
+#endif
+ int i;
+
+ for (i = 0; i < 3500; i++) {
+ if (in8 (dev_base + UART_LSR) & asyncLSRTxHoldEmpty1)
+ break;
+ udelay (100);
+ }
+ MFREG(UART0_SDR, reg);
+ reg &= ~CR0_MASK;
+
+#ifdef CFG_EXT_SERIAL_CLOCK
+ reg |= CR0_EXTCLK_ENA;
+ udiv = 1;
+ tmp = gd->baudrate * 16;
+ bdiv = (CFG_EXT_SERIAL_CLOCK + tmp / 2) / tmp;
+#else
+ /* For 440, the cpu clock is on divider chain A, UART on divider
+ * chain B ... so cpu clock is irrelevant. Get the "optimized"
+ * values that are subject to the 1/2 opb clock constraint
+ */
+ serial_divs (gd->baudrate, &udiv, &bdiv);
+#endif
+
+ reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS; /* set the UART divisor */
+
+ /*
+ * Configure input clock to baudrate generator for all
+ * available serial ports here
+ */
+ MTREG(UART0_SDR, reg);
+#if defined(UART1_SDR)
+ MTREG(UART1_SDR, reg);
+#endif
+#if defined(UART2_SDR)
+ MTREG(UART2_SDR, reg);
+#endif
+#if defined(UART3_SDR)
+ MTREG(UART3_SDR, reg);
+#endif
+
+ out8(dev_base + UART_LCR, 0x80); /* set DLAB bit */
+ out8(dev_base + UART_DLL, bdiv); /* set baudrate divisor */
+ out8(dev_base + UART_DLM, bdiv >> 8); /* set baudrate divisor */
+ out8(dev_base + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */
+ out8(dev_base + UART_FCR, 0x00); /* disable FIFO */
+ out8(dev_base + UART_MCR, 0x10); /* enable loopback mode */
+ val = in8(dev_base + UART_LSR); /* clear line status */
+ val = in8(dev_base + UART_RBR); /* read receive buffer */
+ out8(dev_base + UART_SCR, 0x00); /* set scratchpad */
+ out8(dev_base + UART_IER, 0x00); /* set interrupt enable reg */
+
+ return 0;
+}
+
+#else /* CONFIG_440 */
+
+static int uart_post_init (unsigned long dev_base)
+{
+ unsigned long reg;
+ unsigned long tmp;
+ unsigned long clk;
+ unsigned long udiv;
+ unsigned short bdiv;
+ volatile char val;
+ int i;
+
+ for (i = 0; i < 3500; i++) {
+ if (in8 (dev_base + UART_LSR) & asyncLSRTxHoldEmpty1)
+ break;
+ udelay (100);
+ }
+
+#if defined(CONFIG_405EZ)
+ serial_divs(gd->baudrate, &udiv, &bdiv);
+ clk = tmp = reg = 0;
+#else
+#ifdef CONFIG_405EP
+ reg = mfdcr(cpc0_ucr) & ~(UCR0_MASK | UCR1_MASK);
+ clk = gd->cpu_clk;
+ tmp = CFG_BASE_BAUD * 16;
+ udiv = (clk + tmp / 2) / tmp;
+ if (udiv > UDIV_MAX) /* max. n bits for udiv */
+ udiv = UDIV_MAX;
+ reg |= (udiv) << UCR0_UDIV_POS; /* set the UART divisor */
+ reg |= (udiv) << UCR1_UDIV_POS; /* set the UART divisor */
+ mtdcr (cpc0_ucr, reg);
+#else /* CONFIG_405EP */
+ reg = mfdcr(cntrl0) & ~CR0_MASK;
+#ifdef CFG_EXT_SERIAL_CLOCK
+ clk = CFG_EXT_SERIAL_CLOCK;
+ udiv = 1;
+ reg |= CR0_EXTCLK_ENA;
+#else
+ clk = gd->cpu_clk;
+#ifdef CFG_405_UART_ERRATA_59
+ udiv = 31; /* Errata 59: stuck at 31 */
+#else
+ tmp = CFG_BASE_BAUD * 16;
+ udiv = (clk + tmp / 2) / tmp;
+ if (udiv > UDIV_MAX) /* max. n bits for udiv */
+ udiv = UDIV_MAX;
+#endif
+#endif
+ reg |= (udiv - 1) << CR0_UDIV_POS; /* set the UART divisor */
+ mtdcr (cntrl0, reg);
+#endif /* CONFIG_405EP */
+ tmp = gd->baudrate * udiv * 16;
+ bdiv = (clk + tmp / 2) / tmp;
+#endif /* CONFIG_405EZ */
+
+ out8(dev_base + UART_LCR, 0x80); /* set DLAB bit */
+ out8(dev_base + UART_DLL, bdiv); /* set baudrate divisor */
+ out8(dev_base + UART_DLM, bdiv >> 8); /* set baudrate divisor */
+ out8(dev_base + UART_LCR, 0x03); /* clear DLAB; set 8 bits, no parity */
+ out8(dev_base + UART_FCR, 0x00); /* disable FIFO */
+ out8(dev_base + UART_MCR, 0x10); /* enable loopback mode */
+ val = in8(dev_base + UART_LSR); /* clear line status */
+ val = in8(dev_base + UART_RBR); /* read receive buffer */
+ out8(dev_base + UART_SCR, 0x00); /* set scratchpad */
+ out8(dev_base + UART_IER, 0x00); /* set interrupt enable reg */
+
+ return (0);
+}
+#endif /* CONFIG_440 */
+
+static void uart_post_putc (unsigned long dev_base, char c)
+{
+ int i;
+
+ out8 (dev_base + UART_THR, c); /* put character out */
+
+ /* Wait for transfer completion */
+ for (i = 0; i < 3500; i++) {
+ if (in8 (dev_base + UART_LSR) & asyncLSRTxHoldEmpty1)
+ break;
+ udelay (100);
+ }
+}
+
+static int uart_post_getc (unsigned long dev_base)
+{
+ int i;
+
+ /* Wait for character available */
+ for (i = 0; i < 3500; i++) {
+ if (in8 (dev_base + UART_LSR) & asyncLSRDataReady1)
+ break;
+ udelay (100);
+ }
+ return 0xff & in8 (dev_base + UART_RBR);
+}
+
+static int test_ctlr (unsigned long dev_base, int index)
+{
+ int res = -1;
+ char test_str[] = "*** UART Test String ***\r\n";
+ int i;
+
+ uart_post_init (dev_base);
+
+ for (i = 0; i < sizeof (test_str) - 1; i++) {
+ uart_post_putc (dev_base, test_str[i]);
+ if (uart_post_getc (dev_base) != test_str[i])
+ goto done;
+ }
+ res = 0;
+done:
+ if (res)
+ post_log ("uart%d test failed\n", index);
+
+ return res;
+}
+
+int uart_post_test (int flags)
+{
+ int i, res = 0;
+ static unsigned long base[] = CFG_POST_UART_TABLE;
+
+ for (i = 0; i < sizeof (base) / sizeof (base[0]); i++) {
+ if (test_ctlr (base[i], i))
+ res = -1;
+ }
+ serial_reinit_all ();
+
+ return res;
+}
+
+#endif /* CONFIG_POST & CFG_POST_UART */
+#endif /* CONFIG_POST */
diff --git a/post/cpu/ppc4xx/watchdog.c b/post/cpu/ppc4xx/watchdog.c
new file mode 100644
index 0000000..bd4f4c9
--- /dev/null
+++ b/post/cpu/ppc4xx/watchdog.c
@@ -0,0 +1,71 @@
+/*
+ * (C) Copyright 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Author: Igor Lisitsin <igor@emcraft.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+/*
+ * Watchdog test
+ *
+ * The test verifies the watchdog timer operation.
+ * On the first iteration, the test routine disables interrupts and
+ * makes a 10-second delay. If the system does not reboot during this delay,
+ * the watchdog timer is not operational and the test fails. If the system
+ * reboots, on the second iteration the test routine reports a success.
+ */
+
+#ifdef CONFIG_POST
+
+#include <post.h>
+
+#if CONFIG_POST & CFG_POST_WATCHDOG
+
+#include <watchdog.h>
+
+int watchdog_post_test (int flags)
+{
+ if (flags & POST_REBOOT) {
+ /* Test passed */
+ return 0;
+ }
+ else {
+ /* 10-second delay */
+ int ints = disable_interrupts ();
+ ulong base = post_time_ms (0);
+
+ while (post_time_ms (base) < 10000)
+ ;
+ if (ints)
+ enable_interrupts ();
+
+ /*
+ * If we have reached this point, the watchdog timer
+ * does not work
+ */
+ return -1;
+ }
+}
+
+#endif /* CONFIG_POST & CFG_POST_WATCHDOG */
+#endif /* CONFIG_POST */