summaryrefslogtreecommitdiff
path: root/arch/powerpc/cpu/mpc8220
diff options
context:
space:
mode:
authorStefan Roese <sr@denx.de>2010-04-15 16:07:28 +0200
committerWolfgang Denk <wd@denx.de>2010-04-21 23:42:38 +0200
commita47a12becf66f02a56da91c161e2edb625e9f20c (patch)
tree6efae7137d26d1e610c5fd56b7aaa3c043ad2b71 /arch/powerpc/cpu/mpc8220
parent254ab7bd464657600aba69d840406f9358f3e116 (diff)
downloadu-boot-imx-a47a12becf66f02a56da91c161e2edb625e9f20c.zip
u-boot-imx-a47a12becf66f02a56da91c161e2edb625e9f20c.tar.gz
u-boot-imx-a47a12becf66f02a56da91c161e2edb625e9f20c.tar.bz2
Move arch/ppc to arch/powerpc
As discussed on the list, move "arch/ppc" to "arch/powerpc" to better match the Linux directory structure. Please note that this patch also changes the "ppc" target in MAKEALL to "powerpc" to match this new infrastructure. But "ppc" is kept as an alias for now, to not break compatibility with scripts using this name. Signed-off-by: Stefan Roese <sr@denx.de> Acked-by: Wolfgang Denk <wd@denx.de> Acked-by: Detlev Zundel <dzu@denx.de> Acked-by: Kim Phillips <kim.phillips@freescale.com> Cc: Peter Tyser <ptyser@xes-inc.com> Cc: Anatolij Gustschin <agust@denx.de>
Diffstat (limited to 'arch/powerpc/cpu/mpc8220')
-rw-r--r--arch/powerpc/cpu/mpc8220/Makefile50
-rw-r--r--arch/powerpc/cpu/mpc8220/config.mk30
-rw-r--r--arch/powerpc/cpu/mpc8220/cpu.c104
-rw-r--r--arch/powerpc/cpu/mpc8220/cpu_init.c136
-rw-r--r--arch/powerpc/cpu/mpc8220/dma.h68
-rw-r--r--arch/powerpc/cpu/mpc8220/dramSetup.c752
-rw-r--r--arch/powerpc/cpu/mpc8220/dramSetup.h108
-rw-r--r--arch/powerpc/cpu/mpc8220/fec.c1000
-rw-r--r--arch/powerpc/cpu/mpc8220/fec.h283
-rw-r--r--arch/powerpc/cpu/mpc8220/fec_dma_tasks.S363
-rw-r--r--arch/powerpc/cpu/mpc8220/i2c.c390
-rw-r--r--arch/powerpc/cpu/mpc8220/i2cCore.c627
-rw-r--r--arch/powerpc/cpu/mpc8220/i2cCore.h103
-rw-r--r--arch/powerpc/cpu/mpc8220/interrupts.c80
-rw-r--r--arch/powerpc/cpu/mpc8220/io.S128
-rw-r--r--arch/powerpc/cpu/mpc8220/loadtask.c78
-rw-r--r--arch/powerpc/cpu/mpc8220/pci.c191
-rw-r--r--arch/powerpc/cpu/mpc8220/speed.c123
-rw-r--r--arch/powerpc/cpu/mpc8220/start.S750
-rw-r--r--arch/powerpc/cpu/mpc8220/traps.c236
-rw-r--r--arch/powerpc/cpu/mpc8220/u-boot.lds122
-rw-r--r--arch/powerpc/cpu/mpc8220/uart.c126
22 files changed, 5848 insertions, 0 deletions
diff --git a/arch/powerpc/cpu/mpc8220/Makefile b/arch/powerpc/cpu/mpc8220/Makefile
new file mode 100644
index 0000000..b4fad28
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2003-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
+
+LIB = $(obj)lib$(CPU).a
+
+START = start.o
+SOBJS = io.o fec_dma_tasks.o
+COBJS = cpu.o cpu_init.o dramSetup.o fec.o i2c.o \
+ interrupts.o loadtask.o speed.o \
+ traps.o uart.o pci.o
+
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc8220/config.mk b/arch/powerpc/cpu/mpc8220/config.mk
new file mode 100644
index 0000000..e706883
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/config.mk
@@ -0,0 +1,30 @@
+#
+# (C) Copyright 2003
+# 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_MPC8220 -ffixed-r2 \
+ -mstring -mcpu=603e -mmultiple
+
+# Use default linker script. Board port can override in board/*/config.mk
+LDSCRIPT := $(SRCTREE)/arch/powerpc/cpu/mpc8220/u-boot.lds
diff --git a/arch/powerpc/cpu/mpc8220/cpu.c b/arch/powerpc/cpu/mpc8220/cpu.c
new file mode 100644
index 0000000..563cfe0
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/cpu.c
@@ -0,0 +1,104 @@
+/*
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * CPU specific code for the MPC8220 CPUs
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc8220.h>
+#include <netdev.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu (void)
+{
+ ulong clock = gd->cpu_clk;
+ char buf[32];
+
+ puts ("CPU: ");
+
+ printf (CPU_ID_STR);
+
+ printf (" (JTAG ID %08lx)", *(vu_long *) (CONFIG_SYS_MBAR + 0x50));
+
+ printf (" at %s MHz\n", strmhz (buf, clock));
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ volatile gptmr8220_t *gptmr = (volatile gptmr8220_t *) MMAP_GPTMR;
+ ulong msr;
+
+ /* Interrupts and MMU off */
+ __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
+
+ msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
+ __asm__ __volatile__ ("mtmsr %0"::"r" (msr));
+
+ /* Charge the watchdog timer */
+ gptmr->Prescl = 10;
+ gptmr->Count = 1;
+
+ gptmr->Mode = GPT_TMS_SGPIO;
+
+ gptmr->Control = GPT_CTRL_WDEN | GPT_CTRL_CE;
+
+ return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ */
+unsigned long get_tbclk (void)
+{
+ ulong tbclk;
+
+ tbclk = (gd->bus_clk + 3L) / 4L;
+
+ return (tbclk);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_MPC8220_FEC)
+ mpc8220_fec_initialize(bis);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8220/cpu_init.c b/arch/powerpc/cpu/mpc8220/cpu_init.c
new file mode 100644
index 0000000..8f52c7d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/cpu_init.c
@@ -0,0 +1,136 @@
+/*
+ * (C) Copyright 2000-2003
+ * 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 <mpc8220.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers.
+ */
+void cpu_init_f (void)
+{
+ volatile flexbus8220_t *flexbus = (volatile flexbus8220_t *) MMAP_FB;
+ volatile pcfg8220_t *portcfg = (volatile pcfg8220_t *) MMAP_PCFG;
+ volatile xlbarb8220_t *xlbarb = (volatile xlbarb8220_t *) MMAP_XLBARB;
+
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+ /* Clear initial global data */
+ memset ((void *) gd, 0, sizeof (gd_t));
+
+ /* Clear all port configuration */
+ portcfg->pcfg0 = 0;
+ portcfg->pcfg1 = 0;
+ portcfg->pcfg2 = 0;
+ portcfg->pcfg3 = 0;
+ portcfg->pcfg2 = CONFIG_SYS_GP1_PORT2_CONFIG;
+ portcfg->pcfg3 = CONFIG_SYS_PCI_PORT3_CONFIG | CONFIG_SYS_GP2_PORT3_CONFIG;
+
+ /*
+ * Flexbus Controller: configure chip selects and enable them
+ */
+#if defined (CONFIG_SYS_CS0_BASE)
+ flexbus->csar0 = CONFIG_SYS_CS0_BASE;
+
+/* Sorcery-C can hang-up after CTRL reg initialization */
+#if defined (CONFIG_SYS_CS0_CTRL)
+ flexbus->cscr0 = CONFIG_SYS_CS0_CTRL;
+#endif
+ flexbus->csmr0 = ((CONFIG_SYS_CS0_MASK - 1) & 0xffff0000) | 1;
+ __asm__ volatile ("sync");
+#endif
+#if defined (CONFIG_SYS_CS1_BASE)
+ flexbus->csar1 = CONFIG_SYS_CS1_BASE;
+ flexbus->cscr1 = CONFIG_SYS_CS1_CTRL;
+ flexbus->csmr1 = ((CONFIG_SYS_CS1_MASK - 1) & 0xffff0000) | 1;
+ __asm__ volatile ("sync");
+#endif
+#if defined (CONFIG_SYS_CS2_BASE)
+ flexbus->csar2 = CONFIG_SYS_CS2_BASE;
+ flexbus->cscr2 = CONFIG_SYS_CS2_CTRL;
+ flexbus->csmr2 = ((CONFIG_SYS_CS2_MASK - 1) & 0xffff0000) | 1;
+ portcfg->pcfg3 |= CONFIG_SYS_CS2_PORT3_CONFIG;
+ __asm__ volatile ("sync");
+#endif
+#if defined (CONFIG_SYS_CS3_BASE)
+ flexbus->csar3 = CONFIG_SYS_CS3_BASE;
+ flexbus->cscr3 = CONFIG_SYS_CS3_CTRL;
+ flexbus->csmr3 = ((CONFIG_SYS_CS3_MASK - 1) & 0xffff0000) | 1;
+ portcfg->pcfg3 |= CONFIG_SYS_CS3_PORT3_CONFIG;
+ __asm__ volatile ("sync");
+#endif
+#if defined (CONFIG_SYS_CS4_BASE)
+ flexbus->csar4 = CONFIG_SYS_CS4_BASE;
+ flexbus->cscr4 = CONFIG_SYS_CS4_CTRL;
+ flexbus->csmr4 = ((CONFIG_SYS_CS4_MASK - 1) & 0xffff0000) | 1;
+ portcfg->pcfg3 |= CONFIG_SYS_CS4_PORT3_CONFIG;
+ __asm__ volatile ("sync");
+#endif
+#if defined (CONFIG_SYS_CS5_BASE)
+ flexbus->csar5 = CONFIG_SYS_CS5_BASE;
+ flexbus->cscr5 = CONFIG_SYS_CS5_CTRL;
+ flexbus->csmr5 = ((CONFIG_SYS_CS5_MASK - 1) & 0xffff0000) | 1;
+ portcfg->pcfg3 |= CONFIG_SYS_CS5_PORT3_CONFIG;
+ __asm__ volatile ("sync");
+#endif
+
+ /* This section of the code cannot place in cpu_init_r(),
+ it will cause the system to hang */
+ /* enable timebase */
+ xlbarb->addrTenTimeOut = 0x1000;
+ xlbarb->dataTenTimeOut = 0x1000;
+ xlbarb->busActTimeOut = 0x2000;
+
+ xlbarb->config = 0x00002000;
+
+ /* Master Priority Enable */
+ xlbarb->mastPriority = 0;
+ xlbarb->mastPriEn = 0xff;
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+ /* this may belongs to disable interrupt section */
+ /* mask all interrupts */
+ *(vu_long *) 0xf0000700 = 0xfffffc00;
+ *(vu_long *) 0xf0000714 |= 0x0001ffff;
+ *(vu_long *) 0xf0000710 &= ~0x00000f00;
+
+ /* route critical ints to normal ints */
+ *(vu_long *) 0xf0000710 |= 0x00000001;
+
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_MPC8220_FEC)
+ /* load FEC microcode */
+ loadtask (0, 2);
+#endif
+ return (0);
+}
diff --git a/arch/powerpc/cpu/mpc8220/dma.h b/arch/powerpc/cpu/mpc8220/dma.h
new file mode 100644
index 0000000..d06ee63
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/dma.h
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on code
+ * (C) Copyright Motorola, Inc., 2000
+ *
+ * MPC8220 dma header file
+ */
+
+#ifndef __MPC8220_DMA_H
+#define __MPC8220_DMA_H
+
+#include <common.h>
+#include <mpc8220.h>
+
+/* Task number assignment */
+#define FEC_RECV_TASK_NO 0
+#define FEC_XMIT_TASK_NO 1
+
+/*---------------------------------------------------------------------
+ * Stuff for Ethernet Tx/Rx tasks
+ *---------------------------------------------------------------------
+ */
+
+/* Layout of Ethernet controller Parameter SRAM area:
+ * ----------------------------------------------------------------
+ * 0x00: TBD_BASE, base address of TX BD ring
+ * 0x04: TBD_NEXT, address of next TX BD to be processed
+ * 0x08: RBD_BASE, base address of RX BD ring
+ * 0x0C: RBD_NEXT, address of next RX BD to be processed
+ * ---------------------------------------------------------------
+ * ALL PARAMETERS ARE ALL LONGWORDS (FOUR BYTES EACH).
+ */
+
+/* base address of SRAM area to store parameters used by Ethernet tasks */
+#define FEC_PARAM_BASE (MMAP_SRAM + 0x5b00)
+
+/* base address of SRAM area for buffer descriptors */
+#define FEC_BD_BASE (MMAP_SRAM + 0x5b20)
+
+/*---------------------------------------------------------------------
+ * common shortcuts used by driver C code
+ *---------------------------------------------------------------------
+ */
+
+/* Disable SmartDMA task */
+#define DMA_TASK_DISABLE(tasknum) \
+{ \
+ volatile ushort *tcr = (ushort *)(MMAP_DMA + 0x0000001c + 2 * tasknum); \
+ *tcr = (*tcr) & (~0x8000); \
+}
+
+/* Enable SmartDMA task */
+#define DMA_TASK_ENABLE(tasknum) \
+{ \
+ volatile ushort *tcr = (ushort *) (MMAP_DMA + 0x0000001c + 2 * tasknum);\
+ *tcr = (*tcr) | 0x8000; \
+}
+
+/* Clear interrupt pending bits */
+#define DMA_CLEAR_IEVENT(tasknum) \
+{ \
+ struct mpc8220_dma *dma = (struct mpc8220_dma *)MMAP_DMA; \
+ dma->IntPend = (1 << tasknum); \
+}
+
+#endif /* __MPC8220_DMA_H */
diff --git a/arch/powerpc/cpu/mpc8220/dramSetup.c b/arch/powerpc/cpu/mpc8220/dramSetup.c
new file mode 100644
index 0000000..52cf133
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/dramSetup.c
@@ -0,0 +1,752 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.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
+ */
+
+/*
+DESCRIPTION
+Read Dram spd and base on its information to calculate the memory size,
+characteristics to initialize the dram on MPC8220
+*/
+
+#include <common.h>
+#include <mpc8220.h>
+#include "i2cCore.h"
+#include "dramSetup.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define SPD_SIZE CONFIG_SYS_SDRAM_SPD_SIZE
+#define DRAM_SPD (CONFIG_SYS_SDRAM_SPD_I2C_ADDR)<<1 /* on Board SPD eeprom */
+#define TOTAL_BANK CONFIG_SYS_SDRAM_TOTAL_BANKS
+
+int spd_status (volatile i2c8220_t * pi2c, u8 sta_bit, u8 truefalse)
+{
+ int i;
+
+ for (i = 0; i < I2C_POLL_COUNT; i++) {
+ if ((pi2c->sr & sta_bit) == (truefalse ? sta_bit : 0))
+ return (OK);
+ }
+
+ return (ERROR);
+}
+
+int spd_clear (volatile i2c8220_t * pi2c)
+{
+ pi2c->adr = 0;
+ pi2c->fdr = 0;
+ pi2c->cr = 0;
+ pi2c->sr = 0;
+
+ return (OK);
+}
+
+int spd_stop (volatile i2c8220_t * pi2c)
+{
+ pi2c->cr &= ~I2C_CTL_STA; /* Generate stop signal */
+ if (spd_status (pi2c, I2C_STA_BB, 0) != OK)
+ return ERROR;
+
+ return (OK);
+}
+
+int spd_readbyte (volatile i2c8220_t * pi2c, u8 * readb, int *index)
+{
+ pi2c->sr &= ~I2C_STA_IF; /* Clear Interrupt Bit */
+ *readb = pi2c->dr; /* Read a byte */
+
+ /*
+ Set I2C_CTRL_TXAK will cause Transfer pending and
+ set I2C_CTRL_STA will cause Interrupt pending
+ */
+ if (*index != 2) {
+ if (spd_status (pi2c, I2C_STA_CF, 1) != OK) /* Transfer not complete? */
+ return ERROR;
+ }
+
+ if (*index != 1) {
+ if (spd_status (pi2c, I2C_STA_IF, 1) != OK)
+ return ERROR;
+ }
+
+ return (OK);
+}
+
+int readSpdData (u8 * spdData)
+{
+ volatile i2c8220_t *pi2cReg;
+ volatile pcfg8220_t *pcfg;
+ u8 slvAdr = DRAM_SPD;
+ u8 Tmp;
+ int Length = SPD_SIZE;
+ int i = 0;
+
+ /* Enable Port Configuration for SDA and SDL signals */
+ pcfg = (volatile pcfg8220_t *) (MMAP_PCFG);
+ __asm__ ("sync");
+ pcfg->pcfg3 &= ~CONFIG_SYS_I2C_PORT3_CONFIG;
+ __asm__ ("sync");
+
+ /* Points the structure to I2c mbar memory offset */
+ pi2cReg = (volatile i2c8220_t *) (MMAP_I2C);
+
+
+ /* Clear FDR, ADR, SR and CR reg */
+ pi2cReg->adr = 0;
+ pi2cReg->fdr = 0;
+ pi2cReg->cr = 0;
+ pi2cReg->sr = 0;
+
+ /* Set for fix XLB Bus Frequency */
+ switch (gd->bus_clk) {
+ case 60000000:
+ pi2cReg->fdr = 0x15;
+ break;
+ case 70000000:
+ pi2cReg->fdr = 0x16;
+ break;
+ case 80000000:
+ pi2cReg->fdr = 0x3a;
+ break;
+ case 90000000:
+ pi2cReg->fdr = 0x17;
+ break;
+ case 100000000:
+ pi2cReg->fdr = 0x3b;
+ break;
+ case 110000000:
+ pi2cReg->fdr = 0x18;
+ break;
+ case 120000000:
+ pi2cReg->fdr = 0x19;
+ break;
+ case 130000000:
+ pi2cReg->fdr = 0x1a;
+ break;
+ }
+
+ pi2cReg->adr = CONFIG_SYS_I2C_SLAVE<<1;
+
+ pi2cReg->cr = I2C_CTL_EN; /* Set Enable */
+
+ /*
+ The I2C bus should be in Idle state. If the bus is busy,
+ clear the STA bit in control register
+ */
+ if (spd_status (pi2cReg, I2C_STA_BB, 0) != OK) {
+ if ((pi2cReg->cr & I2C_CTL_STA) == I2C_CTL_STA)
+ pi2cReg->cr &= ~I2C_CTL_STA;
+
+ /* Check again if it is still busy, return error if found */
+ if (spd_status (pi2cReg, I2C_STA_BB, 1) == OK)
+ return ERROR;
+ }
+
+ pi2cReg->cr |= I2C_CTL_TX; /* Enable the I2c for TX, Ack */
+ pi2cReg->cr |= I2C_CTL_STA; /* Generate start signal */
+
+ if (spd_status (pi2cReg, I2C_STA_BB, 1) != OK)
+ return ERROR;
+
+
+ /* Write slave address */
+ pi2cReg->sr &= ~I2C_STA_IF; /* Clear Interrupt */
+ pi2cReg->dr = slvAdr; /* Write a byte */
+
+ if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) { /* Transfer not complete? */
+ spd_stop (pi2cReg);
+ return ERROR;
+ }
+
+ if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) {
+ spd_stop (pi2cReg);
+ return ERROR;
+ }
+
+
+ /* Issue the offset to start */
+ pi2cReg->sr &= ~I2C_STA_IF; /* Clear Interrupt */
+ pi2cReg->dr = 0; /* Write a byte */
+
+ if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) { /* Transfer not complete? */
+ spd_stop (pi2cReg);
+ return ERROR;
+ }
+
+ if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) {
+ spd_stop (pi2cReg);
+ return ERROR;
+ }
+
+
+ /* Set repeat start */
+ pi2cReg->cr |= I2C_CTL_RSTA; /* Repeat Start */
+
+ pi2cReg->sr &= ~I2C_STA_IF; /* Clear Interrupt */
+ pi2cReg->dr = slvAdr | 1; /* Write a byte */
+
+ if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) { /* Transfer not complete? */
+ spd_stop (pi2cReg);
+ return ERROR;
+ }
+
+ if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) {
+ spd_stop (pi2cReg);
+ return ERROR;
+ }
+
+ if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01))
+ return ERROR;
+
+ pi2cReg->cr &= ~I2C_CTL_TX; /* Set receive mode */
+
+ if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01))
+ return ERROR;
+
+ /* Dummy Read */
+ if (spd_readbyte (pi2cReg, &Tmp, &i) != OK) {
+ spd_stop (pi2cReg);
+ return ERROR;
+ }
+
+ i = 0;
+ while (Length) {
+ if (Length == 2)
+ pi2cReg->cr |= I2C_CTL_TXAK;
+
+ if (Length == 1)
+ pi2cReg->cr &= ~I2C_CTL_STA;
+
+ if (spd_readbyte (pi2cReg, spdData, &Length) != OK) {
+ return spd_stop (pi2cReg);
+ }
+ i++;
+ Length--;
+ spdData++;
+ }
+
+ /* Stop the service */
+ spd_stop (pi2cReg);
+
+ return OK;
+}
+
+int getBankInfo (int bank, draminfo_t * pBank)
+{
+ int status;
+ int checksum;
+ int count;
+ u8 spdData[SPD_SIZE];
+
+
+ if (bank > 2 || pBank == 0) {
+ /* illegal values */
+ return (-42);
+ }
+
+ status = readSpdData (&spdData[0]);
+ if (status < 0)
+ return (-1);
+
+ /* check the checksum */
+ for (count = 0, checksum = 0; count < LOC_CHECKSUM; count++)
+ checksum += spdData[count];
+
+ checksum = checksum - ((checksum / 256) * 256);
+
+ if (checksum != spdData[LOC_CHECKSUM])
+ return (-2);
+
+ /* Get the memory type */
+ if (!
+ ((spdData[LOC_TYPE] == TYPE_DDR)
+ || (spdData[LOC_TYPE] == TYPE_SDR)))
+ /* not one of the types we support */
+ return (-3);
+
+ pBank->type = spdData[LOC_TYPE];
+
+ /* Set logical banks */
+ pBank->banks = spdData[LOC_LOGICAL_BANKS];
+
+ /* Check that we have enough physical banks to cover the bank we are
+ * figuring out. Odd-numbered banks correspond to the second bank
+ * on the device.
+ */
+ if (bank & 1) {
+ /* Second bank of a "device" */
+ if (spdData[LOC_PHYS_BANKS] < 2)
+ /* this bank doesn't exist on the "device" */
+ return (-4);
+
+ if (spdData[LOC_ROWS] & 0xf0)
+ /* Two asymmetric banks */
+ pBank->rows = spdData[LOC_ROWS] >> 4;
+ else
+ pBank->rows = spdData[LOC_ROWS];
+
+ if (spdData[LOC_COLS] & 0xf0)
+ /* Two asymmetric banks */
+ pBank->cols = spdData[LOC_COLS] >> 4;
+ else
+ pBank->cols = spdData[LOC_COLS];
+ } else {
+ /* First bank of a "device" */
+ pBank->rows = spdData[LOC_ROWS];
+ pBank->cols = spdData[LOC_COLS];
+ }
+
+ pBank->width = spdData[LOC_WIDTH_HIGH] << 8 | spdData[LOC_WIDTH_LOW];
+ pBank->bursts = spdData[LOC_BURSTS];
+ pBank->CAS = spdData[LOC_CAS];
+ pBank->CS = spdData[LOC_CS];
+ pBank->WE = spdData[LOC_WE];
+ pBank->Trp = spdData[LOC_Trp];
+ pBank->Trcd = spdData[LOC_Trcd];
+ pBank->buffered = spdData[LOC_Buffered] & 1;
+ pBank->refresh = spdData[LOC_REFRESH];
+
+ return (0);
+}
+
+
+/* checkMuxSetting -- given a row/column device geometry, return a mask
+ * of the valid DRAM controller addr_mux settings for
+ * that geometry.
+ *
+ * Arguments: u8 rows: number of row addresses in this device
+ * u8 columns: number of column addresses in this device
+ *
+ * Returns: a mask of the allowed addr_mux settings for this
+ * geometry. Each bit in the mask represents a
+ * possible addr_mux settings (for example, the
+ * (1<<2) bit in the mask represents the 0b10 setting)/
+ *
+ */
+u8 checkMuxSetting (u8 rows, u8 columns)
+{
+ muxdesc_t *pIdx, *pMux;
+ u8 mask;
+ int lrows, lcolumns;
+ u32 mux[4] = { 0x00080c04, 0x01080d03, 0x02080e02, 0xffffffff };
+
+ /* Setup MuxDescriptor in SRAM space */
+ /* MUXDESC AddressRuns [] = {
+ { 0, 8, 12, 4 }, / setting, columns, rows, extra columns /
+ { 1, 8, 13, 3 }, / setting, columns, rows, extra columns /
+ { 2, 8, 14, 2 }, / setting, columns, rows, extra columns /
+ { 0xff } / list terminator /
+ }; */
+
+ pIdx = (muxdesc_t *) & mux[0];
+
+ /* Check rows x columns against each possible address mux setting */
+ for (pMux = pIdx, mask = 0;; pMux++) {
+ lrows = rows;
+ lcolumns = columns;
+
+ if (pMux->MuxValue == 0xff)
+ break; /* end of list */
+
+ /* For a given mux setting, since we want all the memory in a
+ * device to be contiguous, we want the device "use up" the
+ * address lines such that there are no extra column or row
+ * address lines on the device.
+ */
+
+ lcolumns -= pMux->Columns;
+ if (lcolumns < 0)
+ /* Not enough columns to get to the rows */
+ continue;
+
+ lrows -= pMux->Rows;
+ if (lrows > 0)
+ /* we have extra rows left -- can't do that! */
+ continue;
+
+ /* At this point, we either have to have used up all the
+ * rows or we have to have no columns left.
+ */
+
+ if (lcolumns != 0 && lrows != 0)
+ /* rows AND columns are left. Bad! */
+ continue;
+
+ lcolumns -= pMux->MoreColumns;
+
+ if (lcolumns <= 0)
+ mask |= (1 << pMux->MuxValue);
+ }
+
+ return (mask);
+}
+
+
+u32 dramSetup (void)
+{
+ draminfo_t DramInfo[TOTAL_BANK];
+ draminfo_t *pDramInfo;
+ u32 size, temp, cfg_value, mode_value, refresh;
+ u8 *ptr;
+ u8 bursts, Trp, Trcd, type, buffered;
+ u8 muxmask, rows, columns;
+ int count, banknum;
+ u32 *prefresh, *pIdx;
+ u32 refrate[8] = { 15625, 3900, 7800, 31300,
+ 62500, 125000, 0xffffffff, 0xffffffff
+ };
+ volatile sysconf8220_t *sysconf;
+ volatile memctl8220_t *memctl;
+
+ sysconf = (volatile sysconf8220_t *) MMAP_MBAR;
+ memctl = (volatile memctl8220_t *) MMAP_MEMCTL;
+
+ /* Set everything in the descriptions to zero */
+ ptr = (u8 *) & DramInfo[0];
+ for (count = 0; count < sizeof (DramInfo); count++)
+ *ptr++ = 0;
+
+ for (banknum = 0; banknum < TOTAL_BANK; banknum++)
+ sysconf->cscfg[banknum];
+
+ /* Descriptions of row/column address muxing for various
+ * addr_mux settings.
+ */
+
+ pIdx = prefresh = (u32 *) & refrate[0];
+
+ /* Get all the info for all three logical banks */
+ bursts = 0xff;
+ Trp = 0;
+ Trcd = 0;
+ type = 0;
+ buffered = 0xff;
+ refresh = 0xffffffff;
+ muxmask = 0xff;
+
+ /* Two bank, CS0 and CS1 */
+ for (banknum = 0, pDramInfo = &DramInfo[0];
+ banknum < TOTAL_BANK; banknum++, pDramInfo++) {
+ pDramInfo->ordinal = banknum; /* initial sorting */
+ if (getBankInfo (banknum, pDramInfo) < 0)
+ continue;
+
+ /* get cumulative parameters of all three banks */
+ if (type && pDramInfo->type != type)
+ return 0;
+
+ type = pDramInfo->type;
+ rows = pDramInfo->rows;
+ columns = pDramInfo->cols;
+
+ /* This chip only supports 13 DRAM memory lines, but some devices
+ * have 14 rows. To deal with this, ignore the 14th address line
+ * by limiting the number of rows (and columns) to 13. This will
+ * mean that for 14-row devices we will only be able to use
+ * half of the memory, but it's better than nothing.
+ */
+ if (rows > 13)
+ rows = 13;
+ if (columns > 13)
+ columns = 13;
+
+ pDramInfo->size =
+ ((1 << (rows + columns)) * pDramInfo->width);
+ pDramInfo->size *= pDramInfo->banks;
+ pDramInfo->size >>= 3;
+
+ /* figure out which addr_mux configurations will support this device */
+ muxmask &= checkMuxSetting (rows, columns);
+ if (muxmask == 0)
+ return 0;
+
+ buffered = pDramInfo->buffered;
+ bursts &= pDramInfo->bursts; /* union of all bursts */
+ if (pDramInfo->Trp > Trp) /* worst case (longest) Trp */
+ Trp = pDramInfo->Trp;
+
+ if (pDramInfo->Trcd > Trcd) /* worst case (longest) Trcd */
+ Trcd = pDramInfo->Trcd;
+
+ prefresh = pIdx;
+ /* worst case (shortest) Refresh period */
+ if (refresh > prefresh[pDramInfo->refresh & 7])
+ refresh = prefresh[pDramInfo->refresh & 7];
+
+ } /* for loop */
+
+
+ /* We only allow a burst length of 8! */
+ if (!(bursts & 8))
+ bursts = 8;
+
+ /* Sort the devices. In order to get each chip select region
+ * aligned properly, put the biggest device at the lowest address.
+ * A simple bubble sort will do the trick.
+ */
+ for (banknum = 0, pDramInfo = &DramInfo[0];
+ banknum < TOTAL_BANK; banknum++, pDramInfo++) {
+ int i;
+
+ for (i = 0; i < TOTAL_BANK; i++) {
+ if (pDramInfo->size < DramInfo[i].size &&
+ pDramInfo->ordinal < DramInfo[i].ordinal) {
+ /* If the current bank is smaller, but if the ordinal is also
+ * smaller, swap the ordinals
+ */
+ u8 temp8;
+
+ temp8 = DramInfo[i].ordinal;
+ DramInfo[i].ordinal = pDramInfo->ordinal;
+ pDramInfo->ordinal = temp8;
+ }
+ }
+ }
+
+
+ /* Now figure out the base address for each bank. While
+ * we're at it, figure out how much memory there is.
+ *
+ */
+ size = 0;
+ for (banknum = 0; banknum < TOTAL_BANK; banknum++) {
+ int i;
+
+ for (i = 0; i < TOTAL_BANK; i++) {
+ if (DramInfo[i].ordinal == banknum
+ && DramInfo[i].size != 0) {
+ DramInfo[i].base = size;
+ size += DramInfo[i].size;
+ }
+ }
+ }
+
+ /* Set up the Drive Strength register */
+ sysconf->sdramds = CONFIG_SYS_SDRAM_DRIVE_STRENGTH;
+
+ /* ********************** Cfg 1 ************************* */
+
+ /* Set the single read to read/write/precharge delay */
+ cfg_value = CFG1_SRD2RWP ((type == TYPE_DDR) ? 7 : 0xb);
+
+ /* Set the single write to read/write/precharge delay.
+ * This may or may not be correct. The controller spec
+ * says "tWR", but "tWR" does not appear in the SPD. It
+ * always seems to be 15nsec for the class of device we're
+ * using, which turns out to be 2 clock cycles at 133MHz,
+ * so that's what we're going to use.
+ *
+ * HOWEVER, because of a bug in the controller, for DDR
+ * we need to set this to be the same as the value
+ * calculated for bwt2rwp.
+ */
+ cfg_value |= CFG1_SWT2RWP ((type == TYPE_DDR) ? 7 : 2);
+
+ /* Set the Read CAS latency. We're going to use a CL of
+ * 2.5 for DDR and 2 SDR.
+ */
+ cfg_value |= CFG1_RLATENCY ((type == TYPE_DDR) ? 7 : 2);
+
+
+ /* Set the Active to Read/Write delay. This depends
+ * on Trcd which is reported as nanoseconds times 4.
+ * We want to calculate Trcd (in nanoseconds) times XLB clock (in Hz)
+ * which gives us a dimensionless quantity. Play games with
+ * the divisions so we don't run out of dynamic ranges.
+ */
+ /* account for megaherz and the times 4 */
+ temp = (Trcd * (gd->bus_clk / 1000000)) / 4;
+
+ /* account for nanoseconds and round up, with a minimum value of 2 */
+ temp = ((temp + 999) / 1000) - 1;
+ if (temp < 2)
+ temp = 2;
+
+ cfg_value |= CFG1_ACT2WR (temp);
+
+ /* Set the precharge to active delay. This depends
+ * on Trp which is reported as nanoseconds times 4.
+ * We want to calculate Trp (in nanoseconds) times XLB clock (in Hz)
+ * which gives us a dimensionless quantity. Play games with
+ * the divisions so we don't run out of dynamic ranges.
+ */
+ /* account for megaherz and the times 4 */
+ temp = (Trp * (gd->bus_clk / 1000000)) / 4;
+
+ /* account for nanoseconds and round up, then subtract 1, with a
+ * minumum value of 1 and a maximum value of 7.
+ */
+ temp = (((temp + 999) / 1000) - 1) & 7;
+ if (temp < 1)
+ temp = 1;
+
+ cfg_value |= CFG1_PRE2ACT (temp);
+
+ /* Set refresh to active delay. This depends
+ * on Trfc which is not reported in the SPD.
+ * We'll use a nominal value of 75nsec which is
+ * what the controller spec uses.
+ */
+ temp = (75 * (gd->bus_clk / 1000000));
+ /* account for nanoseconds and round up, then subtract 1 */
+ cfg_value |= CFG1_REF2ACT (((temp + 999) / 1000) - 1);
+
+ /* Set the write latency, using the values given in the controller spec */
+ cfg_value |= CFG1_WLATENCY ((type == TYPE_DDR) ? 3 : 0);
+ memctl->cfg1 = cfg_value; /* cfg 1 */
+ asm volatile ("sync");
+
+
+ /* ********************** Cfg 2 ************************* */
+
+ /* Set the burst read to read/precharge delay */
+ cfg_value = CFG2_BRD2RP ((type == TYPE_DDR) ? 5 : 8);
+
+ /* Set the burst write to read/precharge delay. Semi-magic numbers
+ * based on the controller spec recommendations, assuming tWR is
+ * two clock cycles.
+ */
+ cfg_value |= CFG2_BWT2RWP ((type == TYPE_DDR) ? 7 : 10);
+
+ /* Set the Burst read to write delay. Semi-magic numbers
+ * based on the DRAM controller documentation.
+ */
+ cfg_value |= CFG2_BRD2WT ((type == TYPE_DDR) ? 7 : 0xb);
+
+ /* Set the burst length -- must be 8!! Well, 7, actually, becuase
+ * it's burst lenght minus 1.
+ */
+ cfg_value |= CFG2_BURSTLEN (7);
+ memctl->cfg2 = cfg_value; /* cfg 2 */
+ asm volatile ("sync");
+
+
+ /* ********************** mode ************************* */
+
+ /* Set enable bit, CKE high/low bits, and the DDR/SDR mode bit,
+ * disable automatic refresh.
+ */
+ cfg_value = CTL_MODE_ENABLE | CTL_CKE_HIGH |
+ ((type == TYPE_DDR) ? CTL_DDR_MODE : 0);
+
+ /* Set the address mux based on whichever setting(s) is/are common
+ * to all the devices we have. If there is more than one, choose
+ * one arbitrarily.
+ */
+ if (muxmask & 0x4)
+ cfg_value |= CTL_ADDRMUX (2);
+ else if (muxmask & 0x2)
+ cfg_value |= CTL_ADDRMUX (1);
+ else
+ cfg_value |= CTL_ADDRMUX (0);
+
+ /* Set the refresh interval. */
+ temp = ((refresh * (gd->bus_clk / 1000000)) / (1000 * 64)) - 1;
+ cfg_value |= CTL_REFRESH_INTERVAL (temp);
+
+ /* Set buffered/non-buffered memory */
+ if (buffered)
+ cfg_value |= CTL_BUFFERED;
+
+ memctl->ctrl = cfg_value; /* ctrl */
+ asm volatile ("sync");
+
+ if (type == TYPE_DDR) {
+ /* issue precharge all */
+ temp = cfg_value | CTL_PRECHARGE_CMD;
+ memctl->ctrl = temp; /* ctrl */
+ asm volatile ("sync");
+ }
+
+
+ /* Set up mode value for CAS latency */
+#if (CONFIG_SYS_SDRAM_CAS_LATENCY==5) /* CL=2.5 */
+ mode_value = (MODE_MODE | MODE_BURSTLEN (MODE_BURSTLEN_8) |
+ MODE_BT_SEQUENTIAL | MODE_CL (MODE_CL_2p5) | MODE_CMD);
+#else
+ mode_value = (MODE_MODE | MODE_BURSTLEN (MODE_BURSTLEN_8) |
+ MODE_BT_SEQUENTIAL | MODE_CL (MODE_CL_2) | MODE_CMD);
+#endif
+ asm volatile ("sync");
+
+ /* Write Extended Mode - enable DLL */
+ if (type == TYPE_DDR) {
+ temp = MODE_EXTENDED | MODE_X_DLL_ENABLE |
+ MODE_X_DS_NORMAL | MODE_CMD;
+ memctl->mode = (temp >> 16); /* mode */
+ asm volatile ("sync");
+
+ /* Write Mode - reset DLL, set CAS latency */
+ temp = mode_value | MODE_OPMODE (MODE_OPMODE_RESETDLL);
+ memctl->mode = (temp >> 16); /* mode */
+ asm volatile ("sync");
+ }
+
+ /* Program the chip selects. */
+ for (banknum = 0; banknum < TOTAL_BANK; banknum++) {
+ if (DramInfo[banknum].size != 0) {
+ u32 mask;
+ int i;
+
+ for (i = 0, mask = 1; i < 32; mask <<= 1, i++) {
+ if (DramInfo[banknum].size & mask)
+ break;
+ }
+ temp = (DramInfo[banknum].base & 0xfff00000) | (i -
+ 1);
+
+ sysconf->cscfg[banknum] = temp;
+ asm volatile ("sync");
+ }
+ }
+
+ /* Wait for DLL lock */
+ udelay (200);
+
+ temp = cfg_value | CTL_PRECHARGE_CMD; /* issue precharge all */
+ memctl->ctrl = temp; /* ctrl */
+ asm volatile ("sync");
+
+ temp = cfg_value | CTL_REFRESH_CMD; /* issue precharge all */
+ memctl->ctrl = temp; /* ctrl */
+ asm volatile ("sync");
+
+ memctl->ctrl = temp; /* ctrl */
+ asm volatile ("sync");
+
+ /* Write Mode - DLL normal */
+ temp = mode_value | MODE_OPMODE (MODE_OPMODE_NORMAL);
+ memctl->mode = (temp >> 16); /* mode */
+ asm volatile ("sync");
+
+ /* Enable refresh, enable DQS's (if DDR), and lock the control register */
+ cfg_value &= ~CTL_MODE_ENABLE; /* lock register */
+ cfg_value |= CTL_REFRESH_ENABLE; /* enable refresh */
+
+ if (type == TYPE_DDR)
+ cfg_value |= CTL_DQSOEN (0xf); /* enable DQS's for DDR */
+
+ memctl->ctrl = cfg_value; /* ctrl */
+ asm volatile ("sync");
+
+ return size;
+}
diff --git a/arch/powerpc/cpu/mpc8220/dramSetup.h b/arch/powerpc/cpu/mpc8220/dramSetup.h
new file mode 100644
index 0000000..3b64e08
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/dramSetup.h
@@ -0,0 +1,108 @@
+/*
+ * dramSetup.h
+ *
+ * Prototypes, etc. for the Motorola MPC8220
+ * embedded cpu chips
+ *
+ * 2004 (c) Freescale, Inc.
+ * Author: TsiChung Liew <Tsi-Chung.Liew@freescale.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
+ */
+#ifndef __INCdramsetuph
+#define __INCdramsetuph
+#ifndef __ASSEMBLY__
+/* Where various things are in the SPD */
+#define LOC_TYPE 2
+#define LOC_CHECKSUM 63
+#define LOC_PHYS_BANKS 5
+#define LOC_LOGICAL_BANKS 17
+#define LOC_ROWS 3
+#define LOC_COLS 4
+#define LOC_WIDTH_HIGH 7
+#define LOC_WIDTH_LOW 6
+#define LOC_REFRESH 12
+#define LOC_BURSTS 16
+#define LOC_CAS 18
+#define LOC_CS 19
+#define LOC_WE 20
+#define LOC_Tcyc 9
+#define LOC_Tac 10
+#define LOC_Trp 27
+#define LOC_Trrd 28
+#define LOC_Trcd 29
+#define LOC_Tras 30
+#define LOC_Buffered 21
+/* Types of memory the SPD can tell us about.
+ * We can actually only use SDRAM and DDR.
+ */
+#define TYPE_DRAM 1 /* plain old dram */
+#define TYPE_EDO 2 /* EDO dram */
+#define TYPE_Nibble 3 /* serial nibble memory */
+#define TYPE_SDR 4 /* SDRAM */
+#define TYPE_ROM 5 /* */
+#define TYPE_SGRRAM 6 /* graphics memory */
+#define TYPE_DDR 7 /* DDR sdram */
+#define SDRAMDS_MASK 0x3 /* each field is 2 bits wide */
+#define SDRAMDS_SBE_SHIFT 8 /* Clock enable drive strength */
+#define SDRAMDS_SBC_SHIFT 6 /* Clocks drive strength */
+#define SDRAMDS_SBA_SHIFT 4 /* Address drive strength */
+#define SDRAMDS_SBS_SHIFT 2 /* SDR DQS drive strength */
+#define SDRAMDS_SBD_SHIFT 0 /* Data and DQS drive strength */
+#define DRIVE_STRENGTH_HIGH 0
+#define DRIVE_STRENGTH_MED 1
+#define DRIVE_STRENGTH_LOW 2
+#define DRIVE_STRENGTH_OFF 3
+
+#define OK 0
+#define ERROR -1
+/* Structure to hold information about address muxing. */
+ typedef struct tagMuxDescriptor {
+ u8 MuxValue;
+ u8 Columns;
+ u8 Rows;
+ u8 MoreColumns;
+} muxdesc_t;
+
+/* Structure to define one physical bank of
+ * memory. Note that dram size in bytes is
+ * (2^^(rows+columns)) * width * banks / 8
+*/
+typedef struct tagDramInfo {
+ u32 size; /* size in bytes */
+ u32 base; /* base address */
+ u8 ordinal; /* where in the memory map will we put this */
+ u8 type;
+ u8 rows;
+ u8 cols;
+ u16 width; /* width of each chip in bits */
+ u8 banks; /* number of chips, aka logical banks */
+ u8 bursts; /* bit-encoded allowable burst length */
+ u8 CAS; /* bit-encoded CAS latency values */
+ u8 CS; /* bit-encoded CS latency values */
+ u8 WE; /* bit-encoded WE latency values */
+ u8 Trp; /* bit-encoded row precharge time */
+ u8 Trcd; /* bit-encoded RAS to CAS delay */
+ u8 buffered; /* buffered or not */
+ u8 refresh; /* encoded refresh rate */
+} draminfo_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __INCdramsetuph */
diff --git a/arch/powerpc/cpu/mpc8220/fec.c b/arch/powerpc/cpu/mpc8220/fec.c
new file mode 100644
index 0000000..992e0ff
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/fec.c
@@ -0,0 +1,1000 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on mpc4200fec.c,
+ * (C) Copyright Motorola, Inc., 2000
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include "dma.h"
+#include "fec.h"
+
+#undef DEBUG
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
+ defined(CONFIG_MPC8220_FEC)
+
+#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#ifdef DEBUG
+static void tfifo_print (char *devname, mpc8220_fec_priv * fec);
+static void rfifo_print (char *devname, mpc8220_fec_priv * fec);
+#endif /* DEBUG */
+
+#ifdef DEBUG
+static u32 local_crc32 (char *string, unsigned int crc_value, int len);
+#endif
+
+typedef struct {
+ u8 data[1500]; /* actual data */
+ int length; /* actual length */
+ int used; /* buffer in use or not */
+ u8 head[16]; /* MAC header(6 + 6 + 2) + 2(aligned) */
+} NBUF;
+
+int fec8220_miiphy_read (char *devname, u8 phyAddr, u8 regAddr, u16 * retVal);
+int fec8220_miiphy_write (char *devname, u8 phyAddr, u8 regAddr, u16 data);
+
+/********************************************************************/
+#ifdef DEBUG
+static void mpc8220_fec_phydump (char *devname)
+{
+ u16 phyStatus, i;
+ u8 phyAddr = CONFIG_PHY_ADDR;
+ u8 reg_mask[] = {
+#if CONFIG_PHY_TYPE == 0x79c874 /* AMD Am79C874 */
+ /* regs to print: 0...7, 16...19, 21, 23, 24 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+#else
+ /* regs to print: 0...8, 16...20 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif
+ };
+
+ for (i = 0; i < 32; i++) {
+ if (reg_mask[i]) {
+ miiphy_read (devname, phyAddr, i, &phyStatus);
+ printf ("Mii reg %d: 0x%04x\n", i, phyStatus);
+ }
+ }
+}
+#endif
+
+/********************************************************************/
+static int mpc8220_fec_rbd_init (mpc8220_fec_priv * fec)
+{
+ int ix;
+ char *data;
+ static int once = 0;
+
+ for (ix = 0; ix < FEC_RBD_NUM; ix++) {
+ if (!once) {
+ data = (char *) malloc (FEC_MAX_PKT_SIZE);
+ if (data == NULL) {
+ printf ("RBD INIT FAILED\n");
+ return -1;
+ }
+ fec->rbdBase[ix].dataPointer = (u32) data;
+ }
+ fec->rbdBase[ix].status = FEC_RBD_EMPTY;
+ fec->rbdBase[ix].dataLength = 0;
+ }
+ once++;
+
+ /*
+ * have the last RBD to close the ring
+ */
+ fec->rbdBase[ix - 1].status |= FEC_RBD_WRAP;
+ fec->rbdIndex = 0;
+
+ return 0;
+}
+
+/********************************************************************/
+static void mpc8220_fec_tbd_init (mpc8220_fec_priv * fec)
+{
+ int ix;
+
+ for (ix = 0; ix < FEC_TBD_NUM; ix++) {
+ fec->tbdBase[ix].status = 0;
+ }
+
+ /*
+ * Have the last TBD to close the ring
+ */
+ fec->tbdBase[ix - 1].status |= FEC_TBD_WRAP;
+
+ /*
+ * Initialize some indices
+ */
+ fec->tbdIndex = 0;
+ fec->usedTbdIndex = 0;
+ fec->cleanTbdNum = FEC_TBD_NUM;
+}
+
+/********************************************************************/
+static void mpc8220_fec_rbd_clean (mpc8220_fec_priv * fec, FEC_RBD * pRbd)
+{
+ /*
+ * Reset buffer descriptor as empty
+ */
+ if ((fec->rbdIndex) == (FEC_RBD_NUM - 1))
+ pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY);
+ else
+ pRbd->status = FEC_RBD_EMPTY;
+
+ pRbd->dataLength = 0;
+
+ /*
+ * Now, we have an empty RxBD, restart the SmartDMA receive task
+ */
+ DMA_TASK_ENABLE (FEC_RECV_TASK_NO);
+
+ /*
+ * Increment BD count
+ */
+ fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM;
+}
+
+/********************************************************************/
+static void mpc8220_fec_tbd_scrub (mpc8220_fec_priv * fec)
+{
+ FEC_TBD *pUsedTbd;
+
+#ifdef DEBUG
+ printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n",
+ fec->cleanTbdNum, fec->usedTbdIndex);
+#endif
+
+ /*
+ * process all the consumed TBDs
+ */
+ while (fec->cleanTbdNum < FEC_TBD_NUM) {
+ pUsedTbd = &fec->tbdBase[fec->usedTbdIndex];
+ if (pUsedTbd->status & FEC_TBD_READY) {
+#ifdef DEBUG
+ printf ("Cannot clean TBD %d, in use\n",
+ fec->cleanTbdNum);
+#endif
+ return;
+ }
+
+ /*
+ * clean this buffer descriptor
+ */
+ if (fec->usedTbdIndex == (FEC_TBD_NUM - 1))
+ pUsedTbd->status = FEC_TBD_WRAP;
+ else
+ pUsedTbd->status = 0;
+
+ /*
+ * update some indeces for a correct handling of the TBD ring
+ */
+ fec->cleanTbdNum++;
+ fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM;
+ }
+}
+
+/********************************************************************/
+static void mpc8220_fec_set_hwaddr (mpc8220_fec_priv * fec, char *mac)
+{
+ u8 currByte; /* byte for which to compute the CRC */
+ int byte; /* loop - counter */
+ int bit; /* loop - counter */
+ u32 crc = 0xffffffff; /* initial value */
+
+ /*
+ * The algorithm used is the following:
+ * we loop on each of the six bytes of the provided address,
+ * and we compute the CRC by left-shifting the previous
+ * value by one position, so that each bit in the current
+ * byte of the address may contribute the calculation. If
+ * the latter and the MSB in the CRC are different, then
+ * the CRC value so computed is also ex-ored with the
+ * "polynomium generator". The current byte of the address
+ * is also shifted right by one bit at each iteration.
+ * This is because the CRC generatore in hardware is implemented
+ * as a shift-register with as many ex-ores as the radixes
+ * in the polynomium. This suggests that we represent the
+ * polynomiumm itself as a 32-bit constant.
+ */
+ for (byte = 0; byte < 6; byte++) {
+ currByte = mac[byte];
+ for (bit = 0; bit < 8; bit++) {
+ if ((currByte & 0x01) ^ (crc & 0x01)) {
+ crc >>= 1;
+ crc = crc ^ 0xedb88320;
+ } else {
+ crc >>= 1;
+ }
+ currByte >>= 1;
+ }
+ }
+
+ crc = crc >> 26;
+
+ /*
+ * Set individual hash table register
+ */
+ if (crc >= 32) {
+ fec->eth->iaddr1 = (1 << (crc - 32));
+ fec->eth->iaddr2 = 0;
+ } else {
+ fec->eth->iaddr1 = 0;
+ fec->eth->iaddr2 = (1 << crc);
+ }
+
+ /*
+ * Set physical address
+ */
+ fec->eth->paddr1 =
+ (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
+ fec->eth->paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
+}
+
+/********************************************************************/
+static int mpc8220_fec_init (struct eth_device *dev, bd_t * bis)
+{
+ mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+ struct mpc8220_dma *dma = (struct mpc8220_dma *) MMAP_DMA;
+ const u8 phyAddr = CONFIG_PHY_ADDR; /* Only one PHY */
+
+#ifdef DEBUG
+ printf ("mpc8220_fec_init... Begin\n");
+#endif
+
+ /*
+ * Initialize RxBD/TxBD rings
+ */
+ mpc8220_fec_rbd_init (fec);
+ mpc8220_fec_tbd_init (fec);
+
+ /*
+ * Set up Pin Muxing for FEC 1
+ */
+ *(vu_long *) MMAP_PCFG = 0;
+ *(vu_long *) (MMAP_PCFG + 4) = 0;
+ /*
+ * Clear FEC-Lite interrupt event register(IEVENT)
+ */
+ fec->eth->ievent = 0xffffffff;
+
+ /*
+ * Set interrupt mask register
+ */
+ fec->eth->imask = 0x00000000;
+
+ /*
+ * Set FEC-Lite receive control register(R_CNTRL):
+ */
+ if (fec->xcv_type == SEVENWIRE) {
+ /*
+ * Frame length=1518; 7-wire mode
+ */
+ fec->eth->r_cntrl = 0x05ee0020; /*0x05ee0000;FIXME */
+ } else {
+ /*
+ * Frame length=1518; MII mode;
+ */
+ fec->eth->r_cntrl = 0x05ee0024; /*0x05ee0004;FIXME */
+ }
+
+ fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */
+ if (fec->xcv_type != SEVENWIRE) {
+ /*
+ * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+ * and do not drop the Preamble.
+ */
+ /* tbd - rtm */
+ /*fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); */
+ /* No MII for 7-wire mode */
+ fec->eth->mii_speed = 0x00000030;
+ }
+
+ /*
+ * Set Opcode/Pause Duration Register
+ */
+ fec->eth->op_pause = 0x00010020; /*FIXME0xffff0020; */
+
+ /*
+ * Set Rx FIFO alarm and granularity value
+ */
+ fec->eth->rfifo_cntrl = 0x0c000000;
+ fec->eth->rfifo_alarm = 0x0000030c;
+#ifdef DEBUG
+ if (fec->eth->rfifo_status & 0x00700000) {
+ printf ("mpc8220_fec_init() RFIFO error\n");
+ }
+#endif
+
+ /*
+ * Set Tx FIFO granularity value
+ */
+ /*fec->eth->tfifo_cntrl = 0x0c000000; */ /*tbd - rtm */
+ fec->eth->tfifo_cntrl = 0x0e000000;
+#ifdef DEBUG
+ printf ("tfifo_status: 0x%08x\n", fec->eth->tfifo_status);
+ printf ("tfifo_alarm: 0x%08x\n", fec->eth->tfifo_alarm);
+#endif
+
+ /*
+ * Set transmit fifo watermark register(X_WMRK), default = 64
+ */
+ fec->eth->tfifo_alarm = 0x00000080;
+ fec->eth->x_wmrk = 0x2;
+
+ /*
+ * Set individual address filter for unicast address
+ * and set physical address registers.
+ */
+ mpc8220_fec_set_hwaddr (fec, (char *)(dev->enetaddr));
+
+ /*
+ * Set multicast address filter
+ */
+ fec->eth->gaddr1 = 0x00000000;
+ fec->eth->gaddr2 = 0x00000000;
+
+ /*
+ * Turn ON cheater FSM: ????
+ */
+ fec->eth->xmit_fsm = 0x03000000;
+
+#if 1
+/*#if defined(CONFIG_MPC5200)*/
+ /*
+ * Turn off COMM bus prefetch in the MGT5200 BestComm. It doesn't
+ * work w/ the current receive task.
+ */
+ dma->PtdCntrl |= 0x00000001;
+#endif
+
+ /*
+ * Set priority of different initiators
+ */
+ dma->IPR0 = 7; /* always */
+ dma->IPR3 = 6; /* Eth RX */
+ dma->IPR4 = 5; /* Eth Tx */
+
+ /*
+ * Clear SmartDMA task interrupt pending bits
+ */
+ DMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
+
+ /*
+ * Initialize SmartDMA parameters stored in SRAM
+ */
+ *(int *) FEC_TBD_BASE = (int) fec->tbdBase;
+ *(int *) FEC_RBD_BASE = (int) fec->rbdBase;
+ *(int *) FEC_TBD_NEXT = (int) fec->tbdBase;
+ *(int *) FEC_RBD_NEXT = (int) fec->rbdBase;
+
+ if (fec->xcv_type != SEVENWIRE) {
+ /*
+ * Initialize PHY(LXT971A):
+ *
+ * Generally, on power up, the LXT971A reads its configuration
+ * pins to check for forced operation, If not cofigured for
+ * forced operation, it uses auto-negotiation/parallel detection
+ * to automatically determine line operating conditions.
+ * If the PHY device on the other side of the link supports
+ * auto-negotiation, the LXT971A auto-negotiates with it
+ * using Fast Link Pulse(FLP) Bursts. If the PHY partner does not
+ * support auto-negotiation, the LXT971A automatically detects
+ * the presence of either link pulses(10Mbps PHY) or Idle
+ * symbols(100Mbps) and sets its operating conditions accordingly.
+ *
+ * When auto-negotiation is controlled by software, the following
+ * steps are recommended.
+ *
+ * Note:
+ * The physical address is dependent on hardware configuration.
+ *
+ */
+ int timeout = 1;
+ u16 phyStatus;
+
+ /*
+ * Reset PHY, then delay 300ns
+ */
+ miiphy_write (dev->name, phyAddr, 0x0, 0x8000);
+ udelay (1000);
+
+ if (fec->xcv_type == MII10) {
+ /*
+ * Force 10Base-T, FDX operation
+ */
+#ifdef DEBUG
+ printf ("Forcing 10 Mbps ethernet link... ");
+#endif
+ miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
+ /*
+ miiphy_write(fec, phyAddr, 0x0, 0x0100);
+ */
+ miiphy_write (dev->name, phyAddr, 0x0, 0x0180);
+
+ timeout = 20;
+ do { /* wait for link status to go down */
+ udelay (10000);
+ if ((timeout--) == 0) {
+#ifdef DEBUG
+ printf ("hmmm, should not have waited...");
+#endif
+ break;
+ }
+ miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
+#ifdef DEBUG
+ printf ("=");
+#endif
+ } while ((phyStatus & 0x0004)); /* !link up */
+
+ timeout = 1000;
+ do { /* wait for link status to come back up */
+ udelay (10000);
+ if ((timeout--) == 0) {
+ printf ("failed. Link is down.\n");
+ break;
+ }
+ miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
+#ifdef DEBUG
+ printf ("+");
+#endif
+ } while (!(phyStatus & 0x0004)); /* !link up */
+
+#ifdef DEBUG
+ printf ("done.\n");
+#endif
+ } else { /* MII100 */
+ /*
+ * Set the auto-negotiation advertisement register bits
+ */
+ miiphy_write (dev->name, phyAddr, 0x4, 0x01e1);
+
+ /*
+ * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
+ */
+ miiphy_write (dev->name, phyAddr, 0x0, 0x1200);
+
+ /*
+ * Wait for AN completion
+ */
+ timeout = 5000;
+ do {
+ udelay (1000);
+
+ if ((timeout--) == 0) {
+#ifdef DEBUG
+ printf ("PHY auto neg 0 failed...\n");
+#endif
+ return -1;
+ }
+
+ if (miiphy_read (dev->name, phyAddr, 0x1, &phyStatus) !=
+ 0) {
+#ifdef DEBUG
+ printf ("PHY auto neg 1 failed 0x%04x...\n", phyStatus);
+#endif
+ return -1;
+ }
+ } while (!(phyStatus & 0x0004));
+
+#ifdef DEBUG
+ printf ("PHY auto neg complete! \n");
+#endif
+ }
+
+ }
+
+ /*
+ * Enable FEC-Lite controller
+ */
+ fec->eth->ecntrl |= 0x00000006;
+
+#ifdef DEBUG
+ if (fec->xcv_type != SEVENWIRE)
+ mpc8220_fec_phydump (dev->name);
+#endif
+
+ /*
+ * Enable SmartDMA receive task
+ */
+ DMA_TASK_ENABLE (FEC_RECV_TASK_NO);
+
+#ifdef DEBUG
+ printf ("mpc8220_fec_init... Done \n");
+#endif
+
+ return 1;
+}
+
+/********************************************************************/
+static void mpc8220_fec_halt (struct eth_device *dev)
+{
+ mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+ int counter = 0xffff;
+
+#ifdef DEBUG
+ if (fec->xcv_type != SEVENWIRE)
+ mpc8220_fec_phydump (dev->name);
+#endif
+
+ /*
+ * mask FEC chip interrupts
+ */
+ fec->eth->imask = 0;
+
+ /*
+ * issue graceful stop command to the FEC transmitter if necessary
+ */
+ fec->eth->x_cntrl |= 0x00000001;
+
+ /*
+ * wait for graceful stop to register
+ */
+ while ((counter--) && (!(fec->eth->ievent & 0x10000000)));
+
+ /*
+ * Disable SmartDMA tasks
+ */
+ DMA_TASK_DISABLE (FEC_XMIT_TASK_NO);
+ DMA_TASK_DISABLE (FEC_RECV_TASK_NO);
+
+ /*
+ * Disable the Ethernet Controller
+ */
+ fec->eth->ecntrl &= 0xfffffffd;
+
+ /*
+ * Clear FIFO status registers
+ */
+ fec->eth->rfifo_status &= 0x00700000;
+ fec->eth->tfifo_status &= 0x00700000;
+
+ fec->eth->reset_cntrl = 0x01000000;
+
+ /*
+ * Issue a reset command to the FEC chip
+ */
+ fec->eth->ecntrl |= 0x1;
+
+ /*
+ * wait at least 16 clock cycles
+ */
+ udelay (10);
+
+#ifdef DEBUG
+ printf ("Ethernet task stopped\n");
+#endif
+}
+
+#ifdef DEBUG
+/********************************************************************/
+
+static void tfifo_print (char *devname, mpc8220_fec_priv * fec)
+{
+ u16 phyAddr = CONFIG_PHY_ADDR;
+ u16 phyStatus;
+
+ if ((fec->eth->tfifo_lrf_ptr != fec->eth->tfifo_lwf_ptr)
+ || (fec->eth->tfifo_rdptr != fec->eth->tfifo_wrptr)) {
+
+ miiphy_read (devname, phyAddr, 0x1, &phyStatus);
+ printf ("\nphyStatus: 0x%04x\n", phyStatus);
+ printf ("ecntrl: 0x%08x\n", fec->eth->ecntrl);
+ printf ("ievent: 0x%08x\n", fec->eth->ievent);
+ printf ("x_status: 0x%08x\n", fec->eth->x_status);
+ printf ("tfifo: status 0x%08x\n", fec->eth->tfifo_status);
+
+ printf (" control 0x%08x\n", fec->eth->tfifo_cntrl);
+ printf (" lrfp 0x%08x\n", fec->eth->tfifo_lrf_ptr);
+ printf (" lwfp 0x%08x\n", fec->eth->tfifo_lwf_ptr);
+ printf (" alarm 0x%08x\n", fec->eth->tfifo_alarm);
+ printf (" readptr 0x%08x\n", fec->eth->tfifo_rdptr);
+ printf (" writptr 0x%08x\n", fec->eth->tfifo_wrptr);
+ }
+}
+
+static void rfifo_print (char *devname, mpc8220_fec_priv * fec)
+{
+ u16 phyAddr = CONFIG_PHY_ADDR;
+ u16 phyStatus;
+
+ if ((fec->eth->rfifo_lrf_ptr != fec->eth->rfifo_lwf_ptr)
+ || (fec->eth->rfifo_rdptr != fec->eth->rfifo_wrptr)) {
+
+ miiphy_read (devname, phyAddr, 0x1, &phyStatus);
+ printf ("\nphyStatus: 0x%04x\n", phyStatus);
+ printf ("ecntrl: 0x%08x\n", fec->eth->ecntrl);
+ printf ("ievent: 0x%08x\n", fec->eth->ievent);
+ printf ("x_status: 0x%08x\n", fec->eth->x_status);
+ printf ("rfifo: status 0x%08x\n", fec->eth->rfifo_status);
+
+ printf (" control 0x%08x\n", fec->eth->rfifo_cntrl);
+ printf (" lrfp 0x%08x\n", fec->eth->rfifo_lrf_ptr);
+ printf (" lwfp 0x%08x\n", fec->eth->rfifo_lwf_ptr);
+ printf (" alarm 0x%08x\n", fec->eth->rfifo_alarm);
+ printf (" readptr 0x%08x\n", fec->eth->rfifo_rdptr);
+ printf (" writptr 0x%08x\n", fec->eth->rfifo_wrptr);
+ }
+}
+#endif /* DEBUG */
+
+/********************************************************************/
+
+static int mpc8220_fec_send (struct eth_device *dev, volatile void *eth_data,
+ int data_length)
+{
+ /*
+ * This routine transmits one frame. This routine only accepts
+ * 6-byte Ethernet addresses.
+ */
+ mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+ FEC_TBD *pTbd;
+
+#ifdef DEBUG
+ printf ("tbd status: 0x%04x\n", fec->tbdBase[0].status);
+ tfifo_print (dev->name, fec);
+#endif
+
+ /*
+ * Clear Tx BD ring at first
+ */
+ mpc8220_fec_tbd_scrub (fec);
+
+ /*
+ * Check for valid length of data.
+ */
+ if ((data_length > 1500) || (data_length <= 0)) {
+ return -1;
+ }
+
+ /*
+ * Check the number of vacant TxBDs.
+ */
+ if (fec->cleanTbdNum < 1) {
+#ifdef DEBUG
+ printf ("No available TxBDs ...\n");
+#endif
+ return -1;
+ }
+
+ /*
+ * Get the first TxBD to send the mac header
+ */
+ pTbd = &fec->tbdBase[fec->tbdIndex];
+ pTbd->dataLength = data_length;
+ pTbd->dataPointer = (u32) eth_data;
+ pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
+ fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
+
+#ifdef DEBUG
+ printf ("DMA_TASK_ENABLE, fec->tbdIndex = %d \n", fec->tbdIndex);
+#endif
+
+ /*
+ * Kick the MII i/f
+ */
+ if (fec->xcv_type != SEVENWIRE) {
+ u16 phyStatus;
+
+ miiphy_read (dev->name, 0, 0x1, &phyStatus);
+ }
+
+ /*
+ * Enable SmartDMA transmit task
+ */
+
+#ifdef DEBUG
+ tfifo_print (dev->name, fec);
+#endif
+
+ DMA_TASK_ENABLE (FEC_XMIT_TASK_NO);
+
+#ifdef DEBUG
+ tfifo_print (dev->name, fec);
+#endif
+
+#ifdef DEBUG
+ printf ("+");
+#endif
+
+ fec->cleanTbdNum -= 1;
+
+#ifdef DEBUG
+ printf ("smartDMA ethernet Tx task enabled\n");
+#endif
+ /*
+ * wait until frame is sent .
+ */
+ while (pTbd->status & FEC_TBD_READY) {
+ udelay (10);
+#ifdef DEBUG
+ printf ("TDB status = %04x\n", pTbd->status);
+#endif
+ }
+
+ return 0;
+}
+
+
+/********************************************************************/
+static int mpc8220_fec_recv (struct eth_device *dev)
+{
+ /*
+ * This command pulls one frame from the card
+ */
+ mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
+ FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex];
+ unsigned long ievent;
+ int frame_length, len = 0;
+ NBUF *frame;
+
+#ifdef DEBUG
+ printf ("mpc8220_fec_recv %d Start...\n", fec->rbdIndex);
+ printf ("-");
+#endif
+
+ /*
+ * Check if any critical events have happened
+ */
+ ievent = fec->eth->ievent;
+ fec->eth->ievent = ievent;
+ if (ievent & 0x20060000) {
+ /* BABT, Rx/Tx FIFO errors */
+ mpc8220_fec_halt (dev);
+ mpc8220_fec_init (dev, NULL);
+ return 0;
+ }
+ if (ievent & 0x80000000) {
+ /* Heartbeat error */
+ fec->eth->x_cntrl |= 0x00000001;
+ }
+ if (ievent & 0x10000000) {
+ /* Graceful stop complete */
+ if (fec->eth->x_cntrl & 0x00000001) {
+ mpc8220_fec_halt (dev);
+ fec->eth->x_cntrl &= ~0x00000001;
+ mpc8220_fec_init (dev, NULL);
+ }
+ }
+
+ if (!(pRbd->status & FEC_RBD_EMPTY)) {
+ if ((pRbd->status & FEC_RBD_LAST)
+ && !(pRbd->status & FEC_RBD_ERR)
+ && ((pRbd->dataLength - 4) > 14)) {
+
+ /*
+ * Get buffer address and size
+ */
+ frame = (NBUF *) pRbd->dataPointer;
+ frame_length = pRbd->dataLength - 4;
+
+#if (0)
+ {
+ int i;
+
+ printf ("recv data hdr:");
+ for (i = 0; i < 14; i++)
+ printf ("%x ", *(frame->head + i));
+ printf ("\n");
+ }
+#endif
+ /*
+ * Fill the buffer and pass it to upper layers
+ */
+/* memcpy(buff, frame->head, 14);
+ memcpy(buff + 14, frame->data, frame_length);*/
+ NetReceive ((volatile uchar *) pRbd->dataPointer,
+ frame_length);
+ len = frame_length;
+ }
+ /*
+ * Reset buffer descriptor as empty
+ */
+ mpc8220_fec_rbd_clean (fec, pRbd);
+ }
+ DMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
+ return len;
+}
+
+
+/********************************************************************/
+int mpc8220_fec_initialize (bd_t * bis)
+{
+ mpc8220_fec_priv *fec;
+
+#ifdef CONFIG_HAS_ETH1
+ mpc8220_fec_priv *fec2;
+#endif
+ struct eth_device *dev;
+ char *tmp, *end;
+ char env_enetaddr[6];
+
+#ifdef CONFIG_HAS_ETH1
+ char env_enet1addr[6];
+#endif
+ int i;
+
+ fec = (mpc8220_fec_priv *) malloc (sizeof (*fec));
+ dev = (struct eth_device *) malloc (sizeof (*dev));
+ memset (dev, 0, sizeof *dev);
+
+ fec->eth = (ethernet_regs *) MMAP_FEC1;
+#ifdef CONFIG_HAS_ETH1
+ fec2 = (mpc8220_fec_priv *) malloc (sizeof (*fec));
+ fec2->eth = (ethernet_regs *) MMAP_FEC2;
+#endif
+ fec->tbdBase = (FEC_TBD *) FEC_BD_BASE;
+ fec->rbdBase =
+ (FEC_RBD *) (FEC_BD_BASE + FEC_TBD_NUM * sizeof (FEC_TBD));
+ fec->xcv_type = MII100;
+
+ dev->priv = (void *) fec;
+ dev->iobase = MMAP_FEC1;
+ dev->init = mpc8220_fec_init;
+ dev->halt = mpc8220_fec_halt;
+ dev->send = mpc8220_fec_send;
+ dev->recv = mpc8220_fec_recv;
+
+ sprintf (dev->name, "FEC ETHERNET");
+ eth_register (dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register (dev->name,
+ fec8220_miiphy_read, fec8220_miiphy_write);
+#endif
+
+ /*
+ * Try to set the mac address now. The fec mac address is
+ * a garbage after reset. When not using fec for booting
+ * the Linux fec driver will try to work with this garbage.
+ */
+ tmp = getenv ("ethaddr");
+ if (tmp) {
+ for (i = 0; i < 6; i++) {
+ env_enetaddr[i] =
+ tmp ? simple_strtoul (tmp, &end, 16) : 0;
+ if (tmp)
+ tmp = (*end) ? end + 1 : end;
+ }
+ mpc8220_fec_set_hwaddr (fec, env_enetaddr);
+ }
+#ifdef CONFIG_HAS_ETH1
+ tmp = getenv ("eth1addr");
+ if (tmp) {
+ for (i = 0; i < 6; i++) {
+ env_enet1addr[i] =
+ tmp ? simple_strtoul (tmp, &end, 16) : 0;
+ if (tmp)
+ tmp = (*end) ? end + 1 : end;
+ }
+ mpc8220_fec_set_hwaddr (fec2, env_enet1addr);
+ }
+#endif
+
+ return 1;
+}
+
+/* MII-interface related functions */
+/********************************************************************/
+int fec8220_miiphy_read (char *devname, u8 phyAddr, u8 regAddr, u16 * retVal)
+{
+ ethernet_regs *eth = (ethernet_regs *) MMAP_FEC1;
+ u32 reg; /* convenient holder for the PHY register */
+ u32 phy; /* convenient holder for the PHY */
+ int timeout = 0xffff;
+
+ /*
+ * reading from any PHY's register is done by properly
+ * programming the FEC's MII data register.
+ */
+ reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+ phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+ eth->mii_data =
+ (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy
+ | reg);
+
+ /*
+ * wait for the related interrupt
+ */
+ while ((timeout--) && (!(eth->ievent & 0x00800000)));
+
+ if (timeout == 0) {
+#ifdef DEBUG
+ printf ("Read MDIO failed...\n");
+#endif
+ return -1;
+ }
+
+ /*
+ * clear mii interrupt bit
+ */
+ eth->ievent = 0x00800000;
+
+ /*
+ * it's now safe to read the PHY's register
+ */
+ *retVal = (u16) eth->mii_data;
+
+ return 0;
+}
+
+/********************************************************************/
+int fec8220_miiphy_write (char *devname, u8 phyAddr, u8 regAddr, u16 data)
+{
+ ethernet_regs *eth = (ethernet_regs *) MMAP_FEC1;
+ u32 reg; /* convenient holder for the PHY register */
+ u32 phy; /* convenient holder for the PHY */
+ int timeout = 0xffff;
+
+ reg = regAddr << FEC_MII_DATA_RA_SHIFT;
+ phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
+
+ eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
+ FEC_MII_DATA_TA | phy | reg | data);
+
+ /*
+ * wait for the MII interrupt
+ */
+ while ((timeout--) && (!(eth->ievent & 0x00800000)));
+
+ if (timeout == 0) {
+#ifdef DEBUG
+ printf ("Write MDIO failed...\n");
+#endif
+ return -1;
+ }
+
+ /*
+ * clear MII interrupt bit
+ */
+ eth->ievent = 0x00800000;
+
+ return 0;
+}
+
+#ifdef DEBUG
+static u32 local_crc32 (char *string, unsigned int crc_value, int len)
+{
+ int i;
+ char c;
+ unsigned int crc, count;
+
+ /*
+ * crc32 algorithm
+ */
+ /*
+ * crc = 0xffffffff; * The initialized value should be 0xffffffff
+ */
+ crc = crc_value;
+
+ for (i = len; --i >= 0;) {
+ c = *string++;
+ for (count = 0; count < 8; count++) {
+ if ((c & 0x01) ^ (crc & 0x01)) {
+ crc >>= 1;
+ crc = crc ^ 0xedb88320;
+ } else {
+ crc >>= 1;
+ }
+ c >>= 1;
+ }
+ }
+
+ /*
+ * In big endian system, do byte swaping for crc value
+ */
+ return crc;
+}
+#endif /* DEBUG */
+
+#endif /* CONFIG_MPC8220_FEC */
diff --git a/arch/powerpc/cpu/mpc8220/fec.h b/arch/powerpc/cpu/mpc8220/fec.h
new file mode 100644
index 0000000..a8927fc
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/fec.h
@@ -0,0 +1,283 @@
+/*
+ * (C) Copyright 2003-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on mpc4200fec.h
+ * (C) Copyright Motorola, Inc., 2000
+ *
+ * odin ethernet header file
+ */
+
+#ifndef __MPC8220_FEC_H
+#define __MPC8220_FEC_H
+
+#include <common.h>
+#include <mpc8220.h>
+#include "dma.h"
+
+typedef struct ethernet_register_set {
+
+/* [10:2]addr = 00 */
+
+/* Control and status Registers (offset 000-1FF) */
+
+ volatile u32 fec_id; /* MBAR_ETH + 0x000 */
+ volatile u32 ievent; /* MBAR_ETH + 0x004 */
+ volatile u32 imask; /* MBAR_ETH + 0x008 */
+
+ volatile u32 RES0[1]; /* MBAR_ETH + 0x00C */
+ volatile u32 r_des_active; /* MBAR_ETH + 0x010 */
+ volatile u32 x_des_active; /* MBAR_ETH + 0x014 */
+ volatile u32 r_des_active_cl; /* MBAR_ETH + 0x018 */
+ volatile u32 x_des_active_cl; /* MBAR_ETH + 0x01C */
+ volatile u32 ivent_set; /* MBAR_ETH + 0x020 */
+ volatile u32 ecntrl; /* MBAR_ETH + 0x024 */
+
+ volatile u32 RES1[6]; /* MBAR_ETH + 0x028-03C */
+ volatile u32 mii_data; /* MBAR_ETH + 0x040 */
+ volatile u32 mii_speed; /* MBAR_ETH + 0x044 */
+ volatile u32 mii_status; /* MBAR_ETH + 0x048 */
+
+ volatile u32 RES2[5]; /* MBAR_ETH + 0x04C-05C */
+ volatile u32 mib_data; /* MBAR_ETH + 0x060 */
+ volatile u32 mib_control; /* MBAR_ETH + 0x064 */
+
+ volatile u32 RES3[6]; /* MBAR_ETH + 0x068-7C */
+ volatile u32 r_activate; /* MBAR_ETH + 0x080 */
+ volatile u32 r_cntrl; /* MBAR_ETH + 0x084 */
+ volatile u32 r_hash; /* MBAR_ETH + 0x088 */
+ volatile u32 r_data; /* MBAR_ETH + 0x08C */
+ volatile u32 ar_done; /* MBAR_ETH + 0x090 */
+ volatile u32 r_test; /* MBAR_ETH + 0x094 */
+ volatile u32 r_mib; /* MBAR_ETH + 0x098 */
+ volatile u32 r_da_low; /* MBAR_ETH + 0x09C */
+ volatile u32 r_da_high; /* MBAR_ETH + 0x0A0 */
+
+ volatile u32 RES4[7]; /* MBAR_ETH + 0x0A4-0BC */
+ volatile u32 x_activate; /* MBAR_ETH + 0x0C0 */
+ volatile u32 x_cntrl; /* MBAR_ETH + 0x0C4 */
+ volatile u32 backoff; /* MBAR_ETH + 0x0C8 */
+ volatile u32 x_data; /* MBAR_ETH + 0x0CC */
+ volatile u32 x_status; /* MBAR_ETH + 0x0D0 */
+ volatile u32 x_mib; /* MBAR_ETH + 0x0D4 */
+ volatile u32 x_test; /* MBAR_ETH + 0x0D8 */
+ volatile u32 fdxfc_da1; /* MBAR_ETH + 0x0DC */
+ volatile u32 fdxfc_da2; /* MBAR_ETH + 0x0E0 */
+ volatile u32 paddr1; /* MBAR_ETH + 0x0E4 */
+ volatile u32 paddr2; /* MBAR_ETH + 0x0E8 */
+ volatile u32 op_pause; /* MBAR_ETH + 0x0EC */
+
+ volatile u32 RES5[4]; /* MBAR_ETH + 0x0F0-0FC */
+ volatile u32 instr_reg; /* MBAR_ETH + 0x100 */
+ volatile u32 context_reg; /* MBAR_ETH + 0x104 */
+ volatile u32 test_cntrl; /* MBAR_ETH + 0x108 */
+ volatile u32 acc_reg; /* MBAR_ETH + 0x10C */
+ volatile u32 ones; /* MBAR_ETH + 0x110 */
+ volatile u32 zeros; /* MBAR_ETH + 0x114 */
+ volatile u32 iaddr1; /* MBAR_ETH + 0x118 */
+ volatile u32 iaddr2; /* MBAR_ETH + 0x11C */
+ volatile u32 gaddr1; /* MBAR_ETH + 0x120 */
+ volatile u32 gaddr2; /* MBAR_ETH + 0x124 */
+ volatile u32 random; /* MBAR_ETH + 0x128 */
+ volatile u32 rand1; /* MBAR_ETH + 0x12C */
+ volatile u32 tmp; /* MBAR_ETH + 0x130 */
+
+ volatile u32 RES6[3]; /* MBAR_ETH + 0x134-13C */
+ volatile u32 fifo_id; /* MBAR_ETH + 0x140 */
+ volatile u32 x_wmrk; /* MBAR_ETH + 0x144 */
+ volatile u32 fcntrl; /* MBAR_ETH + 0x148 */
+ volatile u32 r_bound; /* MBAR_ETH + 0x14C */
+ volatile u32 r_fstart; /* MBAR_ETH + 0x150 */
+ volatile u32 r_count; /* MBAR_ETH + 0x154 */
+ volatile u32 r_lag; /* MBAR_ETH + 0x158 */
+ volatile u32 r_read; /* MBAR_ETH + 0x15C */
+ volatile u32 r_write; /* MBAR_ETH + 0x160 */
+ volatile u32 x_count; /* MBAR_ETH + 0x164 */
+ volatile u32 x_lag; /* MBAR_ETH + 0x168 */
+ volatile u32 x_retry; /* MBAR_ETH + 0x16C */
+ volatile u32 x_write; /* MBAR_ETH + 0x170 */
+ volatile u32 x_read; /* MBAR_ETH + 0x174 */
+
+ volatile u32 RES7[2]; /* MBAR_ETH + 0x178-17C */
+ volatile u32 fm_cntrl; /* MBAR_ETH + 0x180 */
+ volatile u32 rfifo_data; /* MBAR_ETH + 0x184 */
+ volatile u32 rfifo_status; /* MBAR_ETH + 0x188 */
+ volatile u32 rfifo_cntrl; /* MBAR_ETH + 0x18C */
+ volatile u32 rfifo_lrf_ptr; /* MBAR_ETH + 0x190 */
+ volatile u32 rfifo_lwf_ptr; /* MBAR_ETH + 0x194 */
+ volatile u32 rfifo_alarm; /* MBAR_ETH + 0x198 */
+ volatile u32 rfifo_rdptr; /* MBAR_ETH + 0x19C */
+ volatile u32 rfifo_wrptr; /* MBAR_ETH + 0x1A0 */
+ volatile u32 tfifo_data; /* MBAR_ETH + 0x1A4 */
+ volatile u32 tfifo_status; /* MBAR_ETH + 0x1A8 */
+ volatile u32 tfifo_cntrl; /* MBAR_ETH + 0x1AC */
+ volatile u32 tfifo_lrf_ptr; /* MBAR_ETH + 0x1B0 */
+ volatile u32 tfifo_lwf_ptr; /* MBAR_ETH + 0x1B4 */
+ volatile u32 tfifo_alarm; /* MBAR_ETH + 0x1B8 */
+ volatile u32 tfifo_rdptr; /* MBAR_ETH + 0x1BC */
+ volatile u32 tfifo_wrptr; /* MBAR_ETH + 0x1C0 */
+
+ volatile u32 reset_cntrl; /* MBAR_ETH + 0x1C4 */
+ volatile u32 xmit_fsm; /* MBAR_ETH + 0x1C8 */
+
+ volatile u32 RES8[3]; /* MBAR_ETH + 0x1CC-1D4 */
+ volatile u32 rdes_data0; /* MBAR_ETH + 0x1D8 */
+ volatile u32 rdes_data1; /* MBAR_ETH + 0x1DC */
+ volatile u32 r_length; /* MBAR_ETH + 0x1E0 */
+ volatile u32 x_length; /* MBAR_ETH + 0x1E4 */
+ volatile u32 x_addr; /* MBAR_ETH + 0x1E8 */
+ volatile u32 cdes_data; /* MBAR_ETH + 0x1EC */
+ volatile u32 status; /* MBAR_ETH + 0x1F0 */
+ volatile u32 dma_control; /* MBAR_ETH + 0x1F4 */
+ volatile u32 des_cmnd; /* MBAR_ETH + 0x1F8 */
+ volatile u32 data; /* MBAR_ETH + 0x1FC */
+
+ /* MIB COUNTERS (Offset 200-2FF) */
+
+ volatile u32 rmon_t_drop; /* MBAR_ETH + 0x200 */
+ volatile u32 rmon_t_packets; /* MBAR_ETH + 0x204 */
+ volatile u32 rmon_t_bc_pkt; /* MBAR_ETH + 0x208 */
+ volatile u32 rmon_t_mc_pkt; /* MBAR_ETH + 0x20C */
+ volatile u32 rmon_t_crc_align; /* MBAR_ETH + 0x210 */
+ volatile u32 rmon_t_undersize; /* MBAR_ETH + 0x214 */
+ volatile u32 rmon_t_oversize; /* MBAR_ETH + 0x218 */
+ volatile u32 rmon_t_frag; /* MBAR_ETH + 0x21C */
+ volatile u32 rmon_t_jab; /* MBAR_ETH + 0x220 */
+ volatile u32 rmon_t_col; /* MBAR_ETH + 0x224 */
+ volatile u32 rmon_t_p64; /* MBAR_ETH + 0x228 */
+ volatile u32 rmon_t_p65to127; /* MBAR_ETH + 0x22C */
+ volatile u32 rmon_t_p128to255; /* MBAR_ETH + 0x230 */
+ volatile u32 rmon_t_p256to511; /* MBAR_ETH + 0x234 */
+ volatile u32 rmon_t_p512to1023; /* MBAR_ETH + 0x238 */
+ volatile u32 rmon_t_p1024to2047;/* MBAR_ETH + 0x23C */
+ volatile u32 rmon_t_p_gte2048; /* MBAR_ETH + 0x240 */
+ volatile u32 rmon_t_octets; /* MBAR_ETH + 0x244 */
+ volatile u32 ieee_t_drop; /* MBAR_ETH + 0x248 */
+ volatile u32 ieee_t_frame_ok; /* MBAR_ETH + 0x24C */
+ volatile u32 ieee_t_1col; /* MBAR_ETH + 0x250 */
+ volatile u32 ieee_t_mcol; /* MBAR_ETH + 0x254 */
+ volatile u32 ieee_t_def; /* MBAR_ETH + 0x258 */
+ volatile u32 ieee_t_lcol; /* MBAR_ETH + 0x25C */
+ volatile u32 ieee_t_excol; /* MBAR_ETH + 0x260 */
+ volatile u32 ieee_t_macerr; /* MBAR_ETH + 0x264 */
+ volatile u32 ieee_t_cserr; /* MBAR_ETH + 0x268 */
+ volatile u32 ieee_t_sqe; /* MBAR_ETH + 0x26C */
+ volatile u32 t_fdxfc; /* MBAR_ETH + 0x270 */
+ volatile u32 ieee_t_octets_ok; /* MBAR_ETH + 0x274 */
+
+ volatile u32 RES9[2]; /* MBAR_ETH + 0x278-27C */
+ volatile u32 rmon_r_drop; /* MBAR_ETH + 0x280 */
+ volatile u32 rmon_r_packets; /* MBAR_ETH + 0x284 */
+ volatile u32 rmon_r_bc_pkt; /* MBAR_ETH + 0x288 */
+ volatile u32 rmon_r_mc_pkt; /* MBAR_ETH + 0x28C */
+ volatile u32 rmon_r_crc_align; /* MBAR_ETH + 0x290 */
+ volatile u32 rmon_r_undersize; /* MBAR_ETH + 0x294 */
+ volatile u32 rmon_r_oversize; /* MBAR_ETH + 0x298 */
+ volatile u32 rmon_r_frag; /* MBAR_ETH + 0x29C */
+ volatile u32 rmon_r_jab; /* MBAR_ETH + 0x2A0 */
+
+ volatile u32 rmon_r_resvd_0; /* MBAR_ETH + 0x2A4 */
+
+ volatile u32 rmon_r_p64; /* MBAR_ETH + 0x2A8 */
+ volatile u32 rmon_r_p65to127; /* MBAR_ETH + 0x2AC */
+ volatile u32 rmon_r_p128to255; /* MBAR_ETH + 0x2B0 */
+ volatile u32 rmon_r_p256to511; /* MBAR_ETH + 0x2B4 */
+ volatile u32 rmon_r_p512to1023; /* MBAR_ETH + 0x2B8 */
+ volatile u32 rmon_r_p1024to2047;/* MBAR_ETH + 0x2BC */
+ volatile u32 rmon_r_p_gte2048; /* MBAR_ETH + 0x2C0 */
+ volatile u32 rmon_r_octets; /* MBAR_ETH + 0x2C4 */
+ volatile u32 ieee_r_drop; /* MBAR_ETH + 0x2C8 */
+ volatile u32 ieee_r_frame_ok; /* MBAR_ETH + 0x2CC */
+ volatile u32 ieee_r_crc; /* MBAR_ETH + 0x2D0 */
+ volatile u32 ieee_r_align; /* MBAR_ETH + 0x2D4 */
+ volatile u32 r_macerr; /* MBAR_ETH + 0x2D8 */
+ volatile u32 r_fdxfc; /* MBAR_ETH + 0x2DC */
+ volatile u32 ieee_r_octets_ok; /* MBAR_ETH + 0x2E0 */
+
+ volatile u32 RES10[6]; /* MBAR_ETH + 0x2E4-2FC */
+
+ volatile u32 RES11[64]; /* MBAR_ETH + 0x300-3FF */
+} ethernet_regs;
+
+/* Receive & Transmit Buffer Descriptor definitions */
+typedef struct BufferDescriptor {
+ u16 status;
+ u16 dataLength;
+ u32 dataPointer;
+} FEC_RBD;
+
+typedef struct {
+ u16 status;
+ u16 dataLength;
+ u32 dataPointer;
+} FEC_TBD;
+
+/* private structure */
+typedef enum {
+ SEVENWIRE, /* 7-wire */
+ MII10, /* MII 10Mbps */
+ MII100 /* MII 100Mbps */
+} xceiver_type;
+
+typedef struct {
+ ethernet_regs *eth;
+ xceiver_type xcv_type; /* transceiver type */
+ FEC_RBD *rbdBase; /* RBD ring */
+ FEC_TBD *tbdBase; /* TBD ring */
+ u16 rbdIndex; /* next receive BD to read */
+ u16 tbdIndex; /* next transmit BD to send */
+ u16 usedTbdIndex; /* next transmit BD to clean */
+ u16 cleanTbdNum; /* the number of available transmit BDs */
+} mpc8220_fec_priv;
+
+/* Ethernet parameter area */
+#define FEC_TBD_BASE (FEC_PARAM_BASE + 0x00)
+#define FEC_TBD_NEXT (FEC_PARAM_BASE + 0x04)
+#define FEC_RBD_BASE (FEC_PARAM_BASE + 0x08)
+#define FEC_RBD_NEXT (FEC_PARAM_BASE + 0x0c)
+
+/* BD Numer definitions */
+#define FEC_TBD_NUM 48 /* The user can adjust this value */
+#define FEC_RBD_NUM 32 /* The user can adjust this value */
+
+/* packet size limit */
+#define FEC_MAX_PKT_SIZE 1536
+
+/* RBD bits definitions */
+#define FEC_RBD_EMPTY 0x8000 /* Buffer is empty */
+#define FEC_RBD_WRAP 0x2000 /* Last BD in ring */
+#define FEC_RBD_INT 0x1000 /* Interrupt */
+#define FEC_RBD_LAST 0x0800 /* Buffer is last in frame(useless) */
+#define FEC_RBD_MISS 0x0100 /* Miss bit for prom mode */
+#define FEC_RBD_BC 0x0080 /* The received frame is broadcast frame */
+#define FEC_RBD_MC 0x0040 /* The received frame is multicast frame */
+#define FEC_RBD_LG 0x0020 /* Frame length violation */
+#define FEC_RBD_NO 0x0010 /* Nonoctet align frame */
+#define FEC_RBD_SH 0x0008 /* Short frame */
+#define FEC_RBD_CR 0x0004 /* CRC error */
+#define FEC_RBD_OV 0x0002 /* Receive FIFO overrun */
+#define FEC_RBD_TR 0x0001 /* Frame is truncated */
+#define FEC_RBD_ERR (FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
+ FEC_RBD_OV | FEC_RBD_TR)
+
+/* TBD bits definitions */
+#define FEC_TBD_READY 0x8000 /* Buffer is ready */
+#define FEC_TBD_WRAP 0x2000 /* Last BD in ring */
+#define FEC_TBD_INT 0x1000 /* Interrupt */
+#define FEC_TBD_LAST 0x0800 /* Buffer is last in frame */
+#define FEC_TBD_TC 0x0400 /* Transmit the CRC */
+#define FEC_TBD_ABC 0x0200 /* Append bad CRC */
+
+/* MII-related definitios */
+#define FEC_MII_DATA_ST 0x40000000 /* Start of frame delimiter */
+#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform a read operation */
+#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform a write operation */
+#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address field mask */
+#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register field mask */
+#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
+#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data field */
+
+#define FEC_MII_DATA_RA_SHIFT 18 /* MII Register address bits */
+#define FEC_MII_DATA_PA_SHIFT 23 /* MII PHY address bits */
+
+#endif /* __MPC8220_FEC_H */
diff --git a/arch/powerpc/cpu/mpc8220/fec_dma_tasks.S b/arch/powerpc/cpu/mpc8220/fec_dma_tasks.S
new file mode 100644
index 0000000..3f8a03b
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/fec_dma_tasks.S
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2004, Freescale Semiconductor, Inc.
+ *
+ * This file contains microcode for the FEC controller of the MPC8220.
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_MPC8220)
+
+/* sas/sccg, gas target */
+.section smartdmaInitData,"aw",@progbits /* Initialized data for task variables */
+.section smartdmaTaskTable,"aw",@progbits /* Task tables */
+.align 9
+.globl taskTable
+taskTable:
+.globl scEthernetRecv_Entry
+scEthernetRecv_Entry: /* Task 0 */
+.long scEthernetRecv_TDT - taskTable /* Task 0 Descriptor Table */
+.long scEthernetRecv_TDT - taskTable + 0x00000094
+.long scEthernetRecv_VarTab - taskTable /* Task 0 Variable Table */
+.long scEthernetRecv_FDT - taskTable + 0x03 /* Task 0 Function Descriptor Table & Flags */
+.long 0x00000000
+.long 0x00000000
+.long scEthernetRecv_CSave - taskTable /* Task 0 context save space */
+.long 0xf0000000
+.globl scEthernetXmit_Entry
+scEthernetXmit_Entry: /* Task 1 */
+.long scEthernetXmit_TDT - taskTable /* Task 1 Descriptor Table */
+.long scEthernetXmit_TDT - taskTable + 0x000000e0
+.long scEthernetXmit_VarTab - taskTable /* Task 1 Variable Table */
+.long scEthernetXmit_FDT - taskTable + 0x03 /* Task 1 Function Descriptor Table & Flags */
+.long 0x00000000
+.long 0x00000000
+.long scEthernetXmit_CSave - taskTable /* Task 1 context save space */
+.long 0xf0000000
+
+
+.globl scEthernetRecv_TDT
+scEthernetRecv_TDT: /* Task 0 Descriptor Table */
+.long 0xc4c50000 /* 0000(153): LCDEXT: idx0 = var9 + var10; idx0 once var0; idx0 += inc0 */
+.long 0x84c5e000 /* 0004(153): LCD: idx1 = var9 + var11; ; idx1 += inc0 */
+.long 0x10001f08 /* 0008(156): DRD1A: var7 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x10000380 /* 000C(157): DRD1A: var0 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x00000f88 /* 0010(158): DRD1A: var3 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long 0x81980000 /* 0014(162): LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */
+.long 0x10000780 /* 0018(164): DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x60000000 /* 001C(165): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long 0x010cf04c /* 0020(165): DRD2B1: var4 = EU3(); EU3(var1,var12) */
+.long 0x82180349 /* 0024(169): LCD: idx0 = var4; idx0 != var13; idx0 += inc1 */
+.long 0x81c68004 /* 0028(172): LCD: idx1 = var3 + var13 + 4; idx1 once var0; idx1 += inc0 */
+.long 0x70000000 /* 002C(174): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x018cf04e /* 0030(174): DRD2B1: var6 = EU3(); EU3(var1,var14) */
+.long 0x70000000 /* 0034(175): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x020cf04f /* 0038(175): DRD2B1: var8 = EU3(); EU3(var1,var15) */
+.long 0x00000b88 /* 003C(176): DRD1A: var2 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long 0x80025184 /* 0040(205): LCDEXT: idx1 = 0xf0009184; ; */
+.long 0x86810412 /* 0044(205): LCD: idx2 = var13, idx3 = var2; idx2 < var16; idx2 += inc2, idx3 += inc2 */
+.long 0x0200cf88 /* 0048(209): DRD1A: *idx3 = *idx1; FN=0 init=16 WS=0 RS=0 */
+.long 0x80025184 /* 004C(217): LCDEXT: idx1 = 0xf0009184; ; */
+.long 0x8681845b /* 0050(217): LCD: idx2 = var13, idx3 = var3; idx2 < var17; idx2 += inc3, idx3 += inc3 */
+.long 0x0000cf88 /* 0054(221): DRD1A: *idx3 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long 0xc31883a4 /* 0058(225): LCDEXT: idx1 = var6; idx1 == var14; idx1 += inc4 */
+.long 0x80190000 /* 005C(225): LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+.long 0x04008468 /* 0060(227): DRD1A: idx1 = var13; FN=0 INT init=0 WS=0 RS=0 */
+.long 0xc4038360 /* 0064(232): LCDEXT: idx1 = var8, idx2 = var7; idx1 == var13; idx1 += inc4, idx2 += inc0 */
+.long 0x81c50000 /* 0068(233): LCD: idx3 = var3 + var10; idx3 once var0; idx3 += inc0 */
+.long 0x1000cb18 /* 006C(235): DRD1A: *idx2 = idx3; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x00000f18 /* 0070(236): DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */
+.long 0xc418836d /* 0074(238): LCDEXT: idx1 = var8; idx1 > var13; idx1 += inc5 */
+.long 0x83990000 /* 0078(238): LCD: idx2 = var7; idx2 once var0; idx2 += inc0 */
+.long 0x10000c00 /* 007C(240): DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x0000c800 /* 0080(241): DRD1A: *idx2 = var0; FN=0 init=0 WS=0 RS=0 */
+.long 0x81988000 /* 0084(245): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long 0x10000788 /* 0088(247): DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x60000000 /* 008C(248): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long 0x080cf04c /* 0090(248): DRD2B1: idx0 = EU3(); EU3(var1,var12) */
+.long 0x000001f8 /* 0094(:0): NOP */
+
+
+.globl scEthernetXmit_TDT
+scEthernetXmit_TDT: /* Task 1 Descriptor Table */
+.long 0x80095b00 /* 0000(280): LCDEXT: idx0 = 0xf0025b00; ; */
+.long 0x85c60004 /* 0004(280): LCD: idx1 = var11 + var12 + 4; idx1 once var0; idx1 += inc0 */
+.long 0x10002308 /* 0008(283): DRD1A: var8 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x10000f88 /* 000C(284): DRD1A: var3 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x00000380 /* 0010(285): DRD1A: var0 = *idx0; FN=0 init=0 WS=0 RS=0 */
+.long 0x81980000 /* 0014(288): LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */
+.long 0x10000780 /* 0018(290): DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x60000000 /* 001C(291): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long 0x024cf04d /* 0020(291): DRD2B1: var9 = EU3(); EU3(var1,var13) */
+.long 0x84980309 /* 0024(294): LCD: idx0 = var9; idx0 != var12; idx0 += inc1 */
+.long 0xc0004003 /* 0028(297): LCDEXT: idx1 = 0x00000003; ; */
+.long 0x81c60004 /* 002C(297): LCD: idx2 = var3 + var12 + 4; idx2 once var0; idx2 += inc0 */
+.long 0x70000000 /* 0030(299): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x010cf04e /* 0034(299): DRD2B1: var4 = EU3(); EU3(var1,var14) */
+.long 0x70000000 /* 0038(300): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x014cf04f /* 003C(300): DRD2B1: var5 = EU3(); EU3(var1,var15) */
+.long 0x70000000 /* 0040(301): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x028cf050 /* 0044(301): DRD2B1: var10 = EU3(); EU3(var1,var16) */
+.long 0x70000000 /* 0048(302): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x018cf051 /* 004C(302): DRD2B1: var6 = EU3(); EU3(var1,var17) */
+.long 0x10000b90 /* 0050(303): DRD1A: var2 = *idx2; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x60000000 /* 0054(304): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long 0x01ccf0a1 /* 0058(304): DRD2B1: var7 = EU3(); EU3(var2,idx1) */
+.long 0xc2988312 /* 005C(308): LCDEXT: idx1 = var5; idx1 > var12; idx1 += inc2 */
+.long 0x83490000 /* 0060(308): LCD: idx2 = var6 + var18; idx2 once var0; idx2 += inc0 */
+.long 0x00001b10 /* 0064(310): DRD1A: var6 = idx2; FN=0 init=0 WS=0 RS=0 */
+.long 0x800251a4 /* 0068(315): LCDEXT: idx1 = 0xf00091a4; ; */
+.long 0xc30104dc /* 006C(315): LCDEXT: idx2 = var6, idx3 = var2; idx2 >= var19; idx2 += inc3, idx3 += inc4 */
+.long 0x839a032d /* 0070(316): LCD: idx4 = var7; idx4 == var12; idx4 += inc5 */
+.long 0x0220c798 /* 0074(321): DRD1A: *idx1 = *idx3; FN=0 init=17 WS=0 RS=0 */
+.long 0x800251a4 /* 0078(329): LCDEXT: idx1 = 0xf00091a4; ; */
+.long 0x99198337 /* 007C(329): LCD: idx2 = idx2, idx3 = idx3; idx2 > var12; idx2 += inc6, idx3 += inc7 */
+.long 0x022ac798 /* 0080(333): DRD1A: *idx1 = *idx3; FN=0 init=17 WS=1 RS=1 */
+.long 0x800251a4 /* 0084(350): LCDEXT: idx1 = 0xf00091a4; ; */
+.long 0xc1430000 /* 0088(350): LCDEXT: idx2 = var2 + var6; idx2 once var0; idx2 += inc0 */
+.long 0x82998312 /* 008C(351): LCD: idx3 = var5; idx3 > var12; idx3 += inc2 */
+.long 0x0a2ac790 /* 0090(354): DRD1A: *idx1 = *idx2; FN=0 TFD init=17 WS=1 RS=1 */
+.long 0x81988000 /* 0094(359): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long 0x60000002 /* 0098(361): DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */
+.long 0x0c4cfc4d /* 009C(361): DRD2B1: *idx1 = EU3(); EU3(*idx1,var13) */
+.long 0xc21883ad /* 00A0(365): LCDEXT: idx1 = var4; idx1 == var14; idx1 += inc5 */
+.long 0x80190000 /* 00A4(365): LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+.long 0x04008460 /* 00A8(367): DRD1A: idx1 = var12; FN=0 INT init=0 WS=0 RS=0 */
+.long 0xc4052305 /* 00AC(371): LCDEXT: idx1 = var8, idx2 = var10; idx2 == var12; idx1 += inc0, idx2 += inc5 */
+.long 0x81ca0000 /* 00B0(372): LCD: idx3 = var3 + var20; idx3 once var0; idx3 += inc0 */
+.long 0x1000c718 /* 00B4(374): DRD1A: *idx1 = idx3; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x00000f18 /* 00B8(375): DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */
+.long 0xc4188000 /* 00BC(378): LCDEXT: idx1 = var8; idx1 once var0; idx1 += inc0 */
+.long 0x85190312 /* 00C0(378): LCD: idx2 = var10; idx2 > var12; idx2 += inc2 */
+.long 0x10000c00 /* 00C4(380): DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x1000c400 /* 00C8(381): DRD1A: *idx1 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x00008860 /* 00CC(382): DRD1A: idx2 = var12; FN=0 init=0 WS=0 RS=0 */
+.long 0x81988000 /* 00D0(386): LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long 0x10000788 /* 00D4(388): DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x60000000 /* 00D8(389): DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long 0x080cf04d /* 00DC(389): DRD2B1: idx0 = EU3(); EU3(var1,var13) */
+.long 0x000001f8 /* 00E0(:0): NOP */
+
+.align 8
+
+.globl scEthernetRecv_VarTab
+scEthernetRecv_VarTab: /* Task 0 Variable Table */
+.long 0x00000000 /* var[0] */
+.long 0x00000000 /* var[1] */
+.long 0x00000000 /* var[2] */
+.long 0x00000000 /* var[3] */
+.long 0x00000000 /* var[4] */
+.long 0x00000000 /* var[5] */
+.long 0x00000000 /* var[6] */
+.long 0x00000000 /* var[7] */
+.long 0x00000000 /* var[8] */
+.long 0xf0025b00 /* var[9] */
+.long 0x00000008 /* var[10] */
+.long 0x0000000c /* var[11] */
+.long 0x80000000 /* var[12] */
+.long 0x00000000 /* var[13] */
+.long 0x10000000 /* var[14] */
+.long 0x20000000 /* var[15] */
+.long 0x00000800 /* var[16] */
+.long 0x00000001 /* var[17] */
+.long 0x00000000 /* var[18] */
+.long 0x00000000 /* var[19] */
+.long 0x00000000 /* var[20] */
+.long 0x00000000 /* var[21] */
+.long 0x00000000 /* var[22] */
+.long 0x00000000 /* var[23] */
+.long 0x00000000 /* inc[0] */
+.long 0x60000000 /* inc[1] */
+.long 0x20000004 /* inc[2] */
+.long 0x20000001 /* inc[3] */
+.long 0x80000000 /* inc[4] */
+.long 0x40000000 /* inc[5] */
+.long 0x00000000 /* inc[6] */
+.long 0x00000000 /* inc[7] */
+
+.align 8
+
+.globl scEthernetXmit_VarTab
+scEthernetXmit_VarTab: /* Task 1 Variable Table */
+.long 0x00000000 /* var[0] */
+.long 0x00000000 /* var[1] */
+.long 0x00000000 /* var[2] */
+.long 0x00000000 /* var[3] */
+.long 0x00000000 /* var[4] */
+.long 0x00000000 /* var[5] */
+.long 0x00000000 /* var[6] */
+.long 0x00000000 /* var[7] */
+.long 0x00000000 /* var[8] */
+.long 0x00000000 /* var[9] */
+.long 0x00000000 /* var[10] */
+.long 0xf0025b00 /* var[11] */
+.long 0x00000000 /* var[12] */
+.long 0x80000000 /* var[13] */
+.long 0x10000000 /* var[14] */
+.long 0x08000000 /* var[15] */
+.long 0x20000000 /* var[16] */
+.long 0x0000ffff /* var[17] */
+.long 0xffffffff /* var[18] */
+.long 0x00000004 /* var[19] */
+.long 0x00000008 /* var[20] */
+.long 0x00000000 /* var[21] */
+.long 0x00000000 /* var[22] */
+.long 0x00000000 /* var[23] */
+.long 0x00000000 /* inc[0] */
+.long 0x60000000 /* inc[1] */
+.long 0x40000000 /* inc[2] */
+.long 0xc000fffc /* inc[3] */
+.long 0xe0000004 /* inc[4] */
+.long 0x80000000 /* inc[5] */
+.long 0x4000ffff /* inc[6] */
+.long 0xe0000001 /* inc[7] */
+
+.align 8
+
+.globl scEthernetRecv_FDT
+scEthernetRecv_FDT: /* Task 0 Function Descriptor Table */
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x21800000 /* and(), EU# 3 */
+.long 0x21e00000 /* or(), EU# 3 */
+.long 0x21400000 /* andn(), EU# 3 */
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+
+.align 8
+
+.globl scEthernetXmit_FDT
+scEthernetXmit_FDT: /* Task 1 Function Descriptor Table */
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x21800000 /* and(), EU# 3 */
+.long 0x21e00000 /* or(), EU# 3 */
+.long 0x21400000 /* andn(), EU# 3 */
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+
+
+.globl scEthernetRecv_CSave
+scEthernetRecv_CSave: /* Task 0 context save space */
+.space 128, 0x0
+
+
+.globl scEthernetXmit_CSave
+scEthernetXmit_CSave: /* Task 1 context save space */
+.space 128, 0x0
+
+#endif
diff --git a/arch/powerpc/cpu/mpc8220/i2c.c b/arch/powerpc/cpu/mpc8220/i2c.c
new file mode 100644
index 0000000..76ecdf1
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/i2c.c
@@ -0,0 +1,390 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.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>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_HARD_I2C
+
+#include <mpc8220.h>
+#include <i2c.h>
+
+typedef struct mpc8220_i2c {
+ volatile u32 adr; /* I2Cn + 0x00 */
+ volatile u32 fdr; /* I2Cn + 0x04 */
+ volatile u32 cr; /* I2Cn + 0x08 */
+ volatile u32 sr; /* I2Cn + 0x0C */
+ volatile u32 dr; /* I2Cn + 0x10 */
+} i2c_t;
+
+/* I2Cn control register bits */
+#define I2C_EN 0x80
+#define I2C_IEN 0x40
+#define I2C_STA 0x20
+#define I2C_TX 0x10
+#define I2C_TXAK 0x08
+#define I2C_RSTA 0x04
+#define I2C_INIT_MASK (I2C_EN | I2C_STA | I2C_TX | I2C_RSTA)
+
+/* I2Cn status register bits */
+#define I2C_CF 0x80
+#define I2C_AAS 0x40
+#define I2C_BB 0x20
+#define I2C_AL 0x10
+#define I2C_SRW 0x04
+#define I2C_IF 0x02
+#define I2C_RXAK 0x01
+
+#define I2C_TIMEOUT 100
+#define I2C_RETRIES 1
+
+struct mpc8220_i2c_tap {
+ int scl2tap;
+ int tap2tap;
+};
+
+static int mpc_reg_in (volatile u32 * reg);
+static void mpc_reg_out (volatile u32 * reg, int val, int mask);
+static int wait_for_bb (void);
+static int wait_for_pin (int *status);
+static int do_address (uchar chip, char rdwr_flag);
+static int send_bytes (uchar chip, char *buf, int len);
+static int receive_bytes (uchar chip, char *buf, int len);
+static int mpc_get_fdr (int);
+
+static int mpc_reg_in (volatile u32 * reg)
+{
+ int ret;
+ ret = *reg >> 24;
+ __asm__ __volatile__ ("eieio");
+ return ret;
+}
+
+static void mpc_reg_out (volatile u32 * reg, int val, int mask)
+{
+ int tmp;
+
+ if (!mask) {
+ *reg = val << 24;
+ } else {
+ tmp = mpc_reg_in (reg);
+ *reg = ((tmp & ~mask) | (val & mask)) << 24;
+ }
+ __asm__ __volatile__ ("eieio");
+
+ return;
+}
+
+static int wait_for_bb (void)
+{
+ i2c_t *regs = (i2c_t *) MMAP_I2C;
+ int timeout = I2C_TIMEOUT;
+ int status;
+
+ status = mpc_reg_in (&regs->sr);
+
+ while (timeout-- && (status & I2C_BB)) {
+#if 1
+ volatile int temp;
+
+ mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+ temp = mpc_reg_in (&regs->dr);
+ mpc_reg_out (&regs->cr, 0, I2C_STA);
+ mpc_reg_out (&regs->cr, 0, 0);
+ mpc_reg_out (&regs->cr, I2C_EN, 0);
+#endif
+ udelay (1000);
+ status = mpc_reg_in (&regs->sr);
+ }
+
+ return (status & I2C_BB);
+}
+
+static int wait_for_pin (int *status)
+{
+ i2c_t *regs = (i2c_t *) MMAP_I2C;
+ int timeout = I2C_TIMEOUT;
+
+ *status = mpc_reg_in (&regs->sr);
+
+ while (timeout-- && !(*status & I2C_IF)) {
+ udelay (1000);
+ *status = mpc_reg_in (&regs->sr);
+ }
+
+ if (!(*status & I2C_IF)) {
+ return -1;
+ }
+
+ mpc_reg_out (&regs->sr, 0, I2C_IF);
+ return 0;
+}
+
+static int do_address (uchar chip, char rdwr_flag)
+{
+ i2c_t *regs = (i2c_t *) MMAP_I2C;
+ int status;
+
+ chip <<= 1;
+
+ if (rdwr_flag)
+ chip |= 1;
+
+ mpc_reg_out (&regs->cr, I2C_TX, I2C_TX);
+ mpc_reg_out (&regs->dr, chip, 0);
+
+ if (wait_for_pin (&status))
+ return -2;
+ if (status & I2C_RXAK)
+ return -3;
+ return 0;
+}
+
+static int send_bytes (uchar chip, char *buf, int len)
+{
+ i2c_t *regs = (i2c_t *) MMAP_I2C;
+ int wrcount;
+ int status;
+
+ for (wrcount = 0; wrcount < len; ++wrcount) {
+
+ mpc_reg_out (&regs->dr, buf[wrcount], 0);
+
+ if (wait_for_pin (&status))
+ break;
+
+ if (status & I2C_RXAK)
+ break;
+
+ }
+
+ return !(wrcount == len);
+ return 0;
+}
+
+static int receive_bytes (uchar chip, char *buf, int len)
+{
+ i2c_t *regs = (i2c_t *) MMAP_I2C;
+ int dummy = 1;
+ int rdcount = 0;
+ int status;
+ int i;
+
+ mpc_reg_out (&regs->cr, 0, I2C_TX);
+
+ for (i = 0; i < len; ++i) {
+ buf[rdcount] = mpc_reg_in (&regs->dr);
+
+ if (dummy)
+ dummy = 0;
+ else
+ rdcount++;
+
+ if (wait_for_pin (&status))
+ return -4;
+ }
+
+ mpc_reg_out (&regs->cr, I2C_TXAK, I2C_TXAK);
+ buf[rdcount++] = mpc_reg_in (&regs->dr);
+
+ if (wait_for_pin (&status))
+ return -5;
+
+ mpc_reg_out (&regs->cr, 0, I2C_TXAK);
+ return 0;
+}
+
+/**************** I2C API ****************/
+
+void i2c_init (int speed, int saddr)
+{
+ i2c_t *regs = (i2c_t *) MMAP_I2C;
+
+ mpc_reg_out (&regs->cr, 0, 0);
+ mpc_reg_out (&regs->adr, saddr << 1, 0);
+
+ /* Set clock
+ */
+ mpc_reg_out (&regs->fdr, mpc_get_fdr (speed), 0);
+
+ /* Enable module
+ */
+ mpc_reg_out (&regs->cr, I2C_EN, I2C_INIT_MASK);
+ mpc_reg_out (&regs->sr, 0, I2C_IF);
+ return;
+}
+
+static int mpc_get_fdr (int speed)
+{
+ static int fdr = -1;
+
+ if (fdr == -1) {
+ ulong best_speed = 0;
+ ulong divider;
+ ulong ipb, scl;
+ ulong bestmatch = 0xffffffffUL;
+ int best_i = 0, best_j = 0, i, j;
+ int SCL_Tap[] = { 9, 10, 12, 15, 5, 6, 7, 8 };
+ struct mpc8220_i2c_tap scltap[] = {
+ {4, 1},
+ {4, 2},
+ {6, 4},
+ {6, 8},
+ {14, 16},
+ {30, 32},
+ {62, 64},
+ {126, 128}
+ };
+
+ ipb = gd->bus_clk;
+ for (i = 7; i >= 0; i--) {
+ for (j = 7; j >= 0; j--) {
+ scl = 2 * (scltap[j].scl2tap +
+ (SCL_Tap[i] -
+ 1) * scltap[j].tap2tap + 2);
+ if (ipb <= speed * scl) {
+ if ((speed * scl - ipb) < bestmatch) {
+ bestmatch = speed * scl - ipb;
+ best_i = i;
+ best_j = j;
+ best_speed = ipb / scl;
+ }
+ }
+ }
+ }
+ divider = (best_i & 3) | ((best_i & 4) << 3) | (best_j << 2);
+ if (gd->flags & GD_FLG_RELOC) {
+ fdr = divider;
+ } else {
+ printf ("%ld kHz, ", best_speed / 1000);
+ return divider;
+ }
+ }
+
+ return fdr;
+}
+
+int i2c_probe (uchar chip)
+{
+ i2c_t *regs = (i2c_t *) MMAP_I2C;
+ int i;
+
+ for (i = 0; i < I2C_RETRIES; i++) {
+ mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+
+ if (!do_address (chip, 0)) {
+ mpc_reg_out (&regs->cr, 0, I2C_STA);
+ break;
+ }
+
+ mpc_reg_out (&regs->cr, 0, I2C_STA);
+ udelay (50);
+ }
+
+ return (i == I2C_RETRIES);
+}
+
+int i2c_read (uchar chip, uint addr, int alen, uchar * buf, int len)
+{
+ uchar xaddr[4];
+ i2c_t *regs = (i2c_t *) MMAP_I2C;
+ int ret = -1;
+
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+
+ if (wait_for_bb ()) {
+ printf ("i2c_read: bus is busy\n");
+ goto Done;
+ }
+
+ mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+ if (do_address (chip, 0)) {
+ printf ("i2c_read: failed to address chip\n");
+ goto Done;
+ }
+
+ if (send_bytes (chip, (char *)&xaddr[4 - alen], alen)) {
+ printf ("i2c_read: send_bytes failed\n");
+ goto Done;
+ }
+
+ mpc_reg_out (&regs->cr, I2C_RSTA, I2C_RSTA);
+ if (do_address (chip, 1)) {
+ printf ("i2c_read: failed to address chip\n");
+ goto Done;
+ }
+
+ if (receive_bytes (chip, (char *)buf, len)) {
+ printf ("i2c_read: receive_bytes failed\n");
+ goto Done;
+ }
+
+ ret = 0;
+ Done:
+ mpc_reg_out (&regs->cr, 0, I2C_STA);
+ return ret;
+}
+
+int i2c_write (uchar chip, uint addr, int alen, uchar * buf, int len)
+{
+ uchar xaddr[4];
+ i2c_t *regs = (i2c_t *) MMAP_I2C;
+ int ret = -1;
+
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+
+ if (wait_for_bb ()) {
+ printf ("i2c_write: bus is busy\n");
+ goto Done;
+ }
+
+ mpc_reg_out (&regs->cr, I2C_STA, I2C_STA);
+ if (do_address (chip, 0)) {
+ printf ("i2c_write: failed to address chip\n");
+ goto Done;
+ }
+
+ if (send_bytes (chip, (char *)&xaddr[4 - alen], alen)) {
+ printf ("i2c_write: send_bytes failed\n");
+ goto Done;
+ }
+
+ if (send_bytes (chip, (char *)buf, len)) {
+ printf ("i2c_write: send_bytes failed\n");
+ goto Done;
+ }
+
+ ret = 0;
+ Done:
+ mpc_reg_out (&regs->cr, 0, I2C_STA);
+ return ret;
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/arch/powerpc/cpu/mpc8220/i2cCore.c b/arch/powerpc/cpu/mpc8220/i2cCore.c
new file mode 100644
index 0000000..b89ad03
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/i2cCore.c
@@ -0,0 +1,627 @@
+/* I2cCore.c - MPC8220 PPC I2C Library */
+
+/* Copyright 2004 Freescale Semiconductor, Inc. */
+
+/*
+modification history
+--------------------
+01c,29jun04,tcl 1.3 removed CR. Added two bytes offset support.
+01b,19jan04,tcl 1.2 removed i2cMsDelay and sysDecGet. renamed i2cMsDelay
+ back to sysMsDelay
+01a,19jan04,tcl 1.1 created and seperated from i2c.c
+*/
+
+/*
+DESCRIPTION
+This file contain I2C low level handling library functions
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vxWorks.h>
+#include <sysLib.h>
+#include <iosLib.h>
+#include <logLib.h>
+#include <tickLib.h>
+
+/* BSP Includes */
+#include "config.h"
+#include "mpc8220.h"
+#include "i2cCore.h"
+
+#ifdef DEBUG_I2CCORE
+int I2CCDbg = 0;
+#endif
+
+#define ABS(x) ((x < 0)? -x : x)
+
+char *I2CERR[16] = {
+ "Transfer in Progress\n", /* 0 */
+ "Transfer complete\n",
+ "Not Addressed\n", /* 2 */
+ "Addressed as a slave\n",
+ "Bus is Idle\n", /* 4 */
+ "Bus is busy\n",
+ "Arbitration Lost\n", /* 6 */
+ "Arbitration on Track\n",
+ "Slave receive, master writing to slave\n", /* 8 */
+ "Slave transmit, master reading from slave\n",
+ "Interrupt is pending\n", /* 10 */
+ "Interrupt complete\n",
+ "Acknowledge received\n", /* 12 */
+ "No acknowledge received\n",
+ "Unknown status\n", /* 14 */
+ "\n"
+};
+
+/******************************************************************************
+ *
+ * chk_status - Check I2C status bit
+ *
+ * RETURNS: OK, or ERROR if the bit encounter
+ *
+ */
+
+STATUS chk_status (PSI2C pi2c, UINT8 sta_bit, UINT8 truefalse)
+{
+ int i, status = 0;
+
+ for (i = 0; i < I2C_POLL_COUNT; i++) {
+ if ((pi2c->sr & sta_bit) == (truefalse ? sta_bit : 0))
+ return (OK);
+ }
+
+ I2CCDBG (L2, ("--- sr %x stabit %x truefalse %d\n",
+ pi2c->sr, sta_bit, truefalse, 0, 0, 0));
+
+ if (i == I2C_POLL_COUNT) {
+ switch (sta_bit) {
+ case I2C_STA_CF:
+ status = 0;
+ break;
+ case I2C_STA_AAS:
+ status = 2;
+ break;
+ case I2C_STA_BB:
+ status = 4;
+ break;
+ case I2C_STA_AL:
+ status = 6;
+ break;
+ case I2C_STA_SRW:
+ status = 8;
+ break;
+ case I2C_STA_IF:
+ status = 10;
+ break;
+ case I2C_STA_RXAK:
+ status = 12;
+ break;
+ default:
+ status = 14;
+ break;
+ }
+
+ if (!truefalse)
+ status++;
+
+ I2CCDBG (NO, ("--- status %d\n", status, 0, 0, 0, 0, 0));
+ I2CCDBG (NO, (I2CERR[status], 0, 0, 0, 0, 0, 0));
+ }
+
+ return (ERROR);
+}
+
+/******************************************************************************
+ *
+ * I2C Enable - Enable the I2C Controller
+ *
+ */
+STATUS i2c_enable (SI2C * pi2c, PI2CSET pi2cSet)
+{
+ int fdr = pi2cSet->bit_rate;
+ UINT8 adr = pi2cSet->i2c_adr;
+
+ I2CCDBG (L2, ("i2c_enable fdr %d adr %x\n", fdr, adr, 0, 0, 0, 0));
+
+ i2c_clear (pi2c); /* Clear FDR, ADR, SR and CR reg */
+
+ SetI2cFDR (pi2c, fdr); /* Frequency */
+ pi2c->adr = adr;
+
+ pi2c->cr = I2C_CTL_EN; /* Set Enable */
+
+ /*
+ The I2C bus should be in Idle state. If the bus is busy,
+ clear the STA bit in control register
+ */
+ if (chk_status (pi2c, I2C_STA_BB, 0) != OK) {
+ if ((pi2c->cr & I2C_CTL_STA) == I2C_CTL_STA)
+ pi2c->cr &= ~I2C_CTL_STA;
+
+ /* Check again if it is still busy, return error if found */
+ if (chk_status (pi2c, I2C_STA_BB, 1) == OK)
+ return ERROR;
+ }
+
+ return (OK);
+}
+
+/******************************************************************************
+ *
+ * I2C Disable - Disable the I2C Controller
+ *
+ */
+STATUS i2c_disable (PSI2C pi2c)
+{
+ i2c_clear (pi2c);
+
+ pi2c->cr &= I2C_CTL_EN; /* Disable I2c */
+
+ if ((pi2c->cr & I2C_CTL_STA) == I2C_CTL_STA)
+ pi2c->cr &= ~I2C_CTL_STA;
+
+ if (chk_status (pi2c, I2C_STA_BB, 0) != OK)
+ return ERROR;
+
+ return (OK);
+}
+
+/******************************************************************************
+ *
+ * I2C Clear - Clear the I2C Controller
+ *
+ */
+STATUS i2c_clear (PSI2C pi2c)
+{
+ pi2c->adr = 0;
+ pi2c->fdr = 0;
+ pi2c->cr = 0;
+ pi2c->sr = 0;
+
+ return (OK);
+}
+
+
+STATUS i2c_start (PSI2C pi2c, PI2CSET pi2cSet)
+{
+#ifdef TWOBYTES
+ UINT16 ByteOffset = pi2cSet->str_adr;
+#else
+ UINT8 ByteOffset = pi2cSet->str_adr;
+#endif
+#if 1
+ UINT8 tmp = 0;
+#endif
+ UINT8 Addr = pi2cSet->slv_adr;
+
+ pi2c->cr |= I2C_CTL_STA; /* Generate start signal */
+
+ if (chk_status (pi2c, I2C_STA_BB, 1) != OK)
+ return ERROR;
+
+ /* Write slave address */
+ if (i2c_writebyte (pi2c, &Addr) != OK) {
+ i2c_stop (pi2c); /* Disable I2c */
+ return ERROR;
+ }
+#ifdef TWOBYTES
+# if 0
+ /* Issue the offset to start */
+ if (i2c_write2byte (pi2c, &ByteOffset) != OK) {
+ i2c_stop (pi2c); /* Disable I2c */
+ return ERROR;
+ }
+#endif
+ tmp = (ByteOffset >> 8) & 0xff;
+ if (i2c_writebyte (pi2c, &tmp) != OK) {
+ i2c_stop (pi2c); /* Disable I2c */
+ return ERROR;
+ }
+ tmp = ByteOffset & 0xff;
+ if (i2c_writebyte (pi2c, &tmp) != OK) {
+ i2c_stop (pi2c); /* Disable I2c */
+ return ERROR;
+ }
+#else
+ if (i2c_writebyte (pi2c, &ByteOffset) != OK) {
+ i2c_stop (pi2c); /* Disable I2c */
+ return ERROR;
+ }
+#endif
+
+ return (OK);
+}
+
+STATUS i2c_stop (PSI2C pi2c)
+{
+ pi2c->cr &= ~I2C_CTL_STA; /* Generate stop signal */
+ if (chk_status (pi2c, I2C_STA_BB, 0) != OK)
+ return ERROR;
+
+ return (OK);
+}
+
+/******************************************************************************
+ *
+ * Read Len bytes to the location pointed to by *Data from the device
+ * with address Addr.
+ */
+int i2c_readblock (SI2C * pi2c, PI2CSET pi2cSet, UINT8 * Data)
+{
+ int i = 0;
+ UINT8 Tmp;
+
+/* UINT8 ByteOffset = pi2cSet->str_adr; not used? */
+ UINT8 Addr = pi2cSet->slv_adr;
+ int Length = pi2cSet->xfer_size;
+
+ I2CCDBG (L1, ("i2c_readblock addr %x data 0x%08x len %d offset %d\n",
+ Addr, (int) Data, Length, ByteOffset, 0, 0));
+
+ if (pi2c->sr & I2C_STA_AL) { /* Check if Arbitration lost */
+ I2CCDBG (FN, ("Arbitration lost\n", 0, 0, 0, 0, 0, 0));
+ pi2c->sr &= ~I2C_STA_AL; /* Clear Arbitration status bit */
+ return ERROR;
+ }
+
+ pi2c->cr |= I2C_CTL_TX; /* Enable the I2c for TX, Ack */
+
+ if (i2c_start (pi2c, pi2cSet) == ERROR)
+ return ERROR;
+
+ pi2c->cr |= I2C_CTL_RSTA; /* Repeat Start */
+
+ Tmp = Addr | 1;
+
+ if (i2c_writebyte (pi2c, &Tmp) != OK) {
+ i2c_stop (pi2c); /* Disable I2c */
+ return ERROR;
+ }
+
+ if (((pi2c->sr & 0x07) == 0x07) || (pi2c->sr & 0x01))
+ return ERROR;
+
+ pi2c->cr &= ~I2C_CTL_TX; /* Set receive mode */
+
+ if (((pi2c->sr & 0x07) == 0x07) || (pi2c->sr & 0x01))
+ return ERROR;
+
+ /* Dummy Read */
+ if (i2c_readbyte (pi2c, &Tmp, &i) != OK) {
+ i2c_stop (pi2c); /* Disable I2c */
+ return ERROR;
+ }
+
+ i = 0;
+ while (Length) {
+ if (Length == 2)
+ pi2c->cr |= I2C_CTL_TXAK;
+
+ if (Length == 1)
+ pi2c->cr &= ~I2C_CTL_STA;
+
+ if (i2c_readbyte (pi2c, Data, &Length) != OK) {
+ return i2c_stop (pi2c);
+ }
+ i++;
+ Length--;
+ Data++;
+ }
+
+ if (i2c_stop (pi2c) == ERROR)
+ return ERROR;
+
+ return i;
+}
+
+STATUS i2c_writeblock (SI2C * pi2c, PI2CSET pi2cSet, UINT8 * Data)
+{
+ int Length = pi2cSet->xfer_size;
+
+#ifdef TWOBYTES
+ UINT16 ByteOffset = pi2cSet->str_adr;
+#else
+ UINT8 ByteOffset = pi2cSet->str_adr;
+#endif
+ int j, k;
+
+ I2CCDBG (L2, ("i2c_writeblock\n", 0, 0, 0, 0, 0, 0));
+
+ if (pi2c->sr & I2C_STA_AL) {
+ /* Check if arbitration lost */
+ I2CCDBG (L2, ("Arbitration lost\n", 0, 0, 0, 0, 0, 0));
+ pi2c->sr &= ~I2C_STA_AL; /* Clear the condition */
+ return ERROR;
+ }
+
+ pi2c->cr |= I2C_CTL_TX; /* Enable the I2c for TX, Ack */
+
+ /* Do the not even offset first */
+ if ((ByteOffset % 8) != 0) {
+ int remain;
+
+ if (Length > 8) {
+ remain = 8 - (ByteOffset % 8);
+ Length -= remain;
+
+ pi2cSet->str_adr = ByteOffset;
+
+ if (i2c_start (pi2c, pi2cSet) == ERROR)
+ return ERROR;
+
+ for (j = ByteOffset; j < remain; j++) {
+ if (i2c_writebyte (pi2c, Data++) != OK)
+ return ERROR;
+ }
+
+ if (i2c_stop (pi2c) == ERROR)
+ return ERROR;
+
+ sysMsDelay (32);
+
+ /* Update the new ByteOffset */
+ ByteOffset += remain;
+ }
+ }
+
+ for (j = ByteOffset, k = 0; j < (Length + ByteOffset); j++) {
+ if ((j % 8) == 0) {
+ pi2cSet->str_adr = j;
+ if (i2c_start (pi2c, pi2cSet) == ERROR)
+ return ERROR;
+ }
+
+ k++;
+
+ if (i2c_writebyte (pi2c, Data++) != OK)
+ return ERROR;
+
+ if ((j == (Length - 1)) || ((k % 8) == 0)) {
+ if (i2c_stop (pi2c) == ERROR)
+ return ERROR;
+
+ sysMsDelay (50);
+ }
+
+ }
+
+ return k;
+}
+
+STATUS i2c_readbyte (SI2C * pi2c, UINT8 * readb, int *index)
+{
+ pi2c->sr &= ~I2C_STA_IF; /* Clear Interrupt Bit */
+ *readb = pi2c->dr; /* Read a byte */
+
+ /*
+ Set I2C_CTRL_TXAK will cause Transfer pending and
+ set I2C_CTRL_STA will cause Interrupt pending
+ */
+ if (*index != 2) {
+ if (chk_status (pi2c, I2C_STA_CF, 1) != OK) /* Transfer not complete? */
+ return ERROR;
+ }
+
+ if (*index != 1) {
+ if (chk_status (pi2c, I2C_STA_IF, 1) != OK)
+ return ERROR;
+ }
+
+ return (OK);
+}
+
+
+STATUS i2c_writebyte (SI2C * pi2c, UINT8 * writeb)
+{
+ pi2c->sr &= ~I2C_STA_IF; /* Clear Interrupt */
+ pi2c->dr = *writeb; /* Write a byte */
+
+ if (chk_status (pi2c, I2C_STA_CF, 1) != OK) /* Transfer not complete? */
+ return ERROR;
+
+ if (chk_status (pi2c, I2C_STA_IF, 1) != OK)
+ return ERROR;
+
+ return OK;
+}
+
+STATUS i2c_write2byte (SI2C * pi2c, UINT16 * writeb)
+{
+ UINT8 data;
+
+ data = (UINT8) ((*writeb >> 8) & 0xff);
+ if (i2c_writebyte (pi2c, &data) != OK)
+ return ERROR;
+ data = (UINT8) (*writeb & 0xff);
+ if (i2c_writebyte (pi2c, &data) != OK)
+ return ERROR;
+ return OK;
+}
+
+/* FDR table base on 33MHz - more detail please refer to Odini2c_dividers.xls
+FDR FDR scl sda scl2tap2
+510 432 tap tap tap tap scl_per sda_hold I2C Freq 0 1 2 3 4 5
+000 000 9 3 4 1 28 Clocks 9 Clocks 1190 KHz 0 0 0 0 0 0
+000 001 9 3 4 2 44 Clocks 11 Clocks 758 KHz 0 0 1 0 0 0
+000 010 9 3 6 4 80 Clocks 17 Clocks 417 KHz 0 0 0 1 0 0
+000 011 9 3 6 8 144 Clocks 25 Clocks 231 KHz 0 0 1 1 0 0
+000 100 9 3 14 16 288 Clocks 49 Clocks 116 KHz 0 0 0 0 1 0
+000 101 9 3 30 32 576 Clocks 97 Clocks 58 KHz 0 0 1 0 1 0
+000 110 9 3 62 64 1152 Clocks 193 Clocks 29 KHz 0 0 0 1 1 0
+000 111 9 3 126 128 2304 Clocks 385 Clocks 14 KHz 0 0 1 1 1 0
+001 000 10 3 4 1 30 Clocks 9 Clocks 1111 KHz1 0 0 0 0 0
+001 001 10 3 4 2 48 Clocks 11 Clocks 694 KHz 1 0 1 0 0 0
+001 010 10 3 6 4 88 Clocks 17 Clocks 379 KHz 1 0 0 1 0 0
+001 011 10 3 6 8 160 Clocks 25 Clocks 208 KHz 1 0 1 1 0 0
+001 100 10 3 14 16 320 Clocks 49 Clocks 104 KHz 1 0 0 0 1 0
+001 101 10 3 30 32 640 Clocks 97 Clocks 52 KHz 1 0 1 0 1 0
+001 110 10 3 62 64 1280 Clocks 193 Clocks 26 KHz 1 0 0 1 1 0
+001 111 10 3 126 128 2560 Clocks 385 Clocks 13 KHz 1 0 1 1 1 0
+010 000 12 4 4 1 34 Clocks 10 Clocks 980 KHz 0 1 0 0 0 0
+010 001 12 4 4 2 56 Clocks 13 Clocks 595 KHz 0 1 1 0 0 0
+010 010 12 4 6 4 104 Clocks 21 Clocks 321 KHz 0 1 0 1 0 0
+010 011 12 4 6 8 192 Clocks 33 Clocks 174 KHz 0 1 1 1 0 0
+010 100 12 4 14 16 384 Clocks 65 Clocks 87 KHz 0 1 0 0 1 0
+010 101 12 4 30 32 768 Clocks 129 Clocks 43 KHz 0 1 1 0 1 0
+010 110 12 4 62 64 1536 Clocks 257 Clocks 22 KHz 0 1 0 1 1 0
+010 111 12 4 126 128 3072 Clocks 513 Clocks 11 KHz 0 1 1 1 1 0
+011 000 15 4 4 1 40 Clocks 10 Clocks 833 KHz 1 1 0 0 0 0
+011 001 15 4 4 2 68 Clocks 13 Clocks 490 KHz 1 1 1 0 0 0
+011 010 15 4 6 4 128 Clocks 21 Clocks 260 KHz 1 1 0 1 0 0
+011 011 15 4 6 8 240 Clocks 33 Clocks 139 KHz 1 1 1 1 0 0
+011 100 15 4 14 16 480 Clocks 65 Clocks 69 KHz 1 1 0 0 1 0
+011 101 15 4 30 32 960 Clocks 129 Clocks 35 KHz 1 1 1 0 1 0
+011 110 15 4 62 64 1920 Clocks 257 Clocks 17 KHz 1 1 0 1 1 0
+011 111 15 4 126 128 3840 Clocks 513 Clocks 9 KHz 1 1 1 1 1 0
+100 000 5 1 4 1 20 Clocks 7 Clocks 1667 KHz 0 0 0 0 0 1
+100 001 5 1 4 2 28 Clocks 7 Clocks 1190 KHz 0 0 1 0 0 1
+100 010 5 1 6 4 48 Clocks 9 Clocks 694 KHz 0 0 0 1 0 1
+100 011 5 1 6 8 80 Clocks 9 Clocks 417 KHz 0 0 1 1 0 1
+100 100 5 1 14 16 160 Clocks 17 Clocks 208 KHz 0 0 0 0 1 1
+100 101 5 1 30 32 320 Clocks 33 Clocks 104 KHz 0 0 1 0 1 1
+100 110 5 1 62 64 640 Clocks 65 Clocks 52 KHz 0 0 0 1 1 1
+100 111 5 1 126 128 1280 Clocks 129 Clocks 26 KHz 0 0 1 1 1 1
+101 000 6 1 4 1 22 Clocks 7 Clocks 1515 KHz 1 0 0 0 0 1
+101 001 6 1 4 2 32 Clocks 7 Clocks 1042 KHz 1 0 1 0 0 1
+101 010 6 1 6 4 56 Clocks 9 Clocks 595 KHz 1 0 0 1 0 1
+101 011 6 1 6 8 96 Clocks 9 Clocks 347 KHz 1 0 1 1 0 1
+101 100 6 1 14 16 192 Clocks 17 Clocks 174 KHz 1 0 0 0 1 1
+101 101 6 1 30 32 384 Clocks 33 Clocks 87 KHz 1 0 1 0 1 1
+101 110 6 1 62 64 768 Clocks 65 Clocks 43 KHz 1 0 0 1 1 1
+101 111 6 1 126 128 1536 Clocks 129 Clocks 22 KHz 1 0 1 1 1 1
+110 000 7 2 4 1 24 Clocks 8 Clocks 1389 KHz 0 1 0 0 0 1
+110 001 7 2 4 2 36 Clocks 9 Clocks 926 KHz 0 1 1 0 0 1
+110 010 7 2 6 4 64 Clocks 13 Clocks 521 KHz 0 1 0 1 0 1
+110 011 7 2 6 8 112 Clocks 17 Clocks 298 KHz 0 1 1 1 0 1
+110 100 7 2 14 16 224 Clocks 33 Clocks 149 KHz 0 1 0 0 1 1
+110 101 7 2 30 32 448 Clocks 65 Clocks 74 KHz 0 1 1 0 1 1
+110 110 7 2 62 64 896 Clocks 129 Clocks 37 KHz 0 1 0 1 1 1
+110 111 7 2 126 128 1792 Clocks 257 Clocks 19 KHz 0 1 1 1 1 1
+111 000 8 2 4 1 26 Clocks 8 Clocks 1282 KHz 1 1 0 0 0 1
+111 001 8 2 4 2 40 Clocks 9 Clocks 833 KHz 1 1 1 0 0 1
+111 010 8 2 6 4 72 Clocks 13 Clocks 463 KHz 1 1 0 1 0 1
+111 011 8 2 6 8 128 Clocks 17 Clocks 260 KHz 1 1 1 1 0 1
+111 100 8 2 14 16 256 Clocks 33 Clocks 130 KHz 1 1 0 0 1 1
+111 101 8 2 30 32 512 Clocks 65 Clocks 65 KHz 1 1 1 0 1 1
+111 110 8 2 62 64 1024 Clocks 129 Clocks 33 KHz 1 1 0 1 1 1
+111 111 8 2 126 128 2048 Clocks 257 Clocks 16 KHz 1 1 1 1 1 1
+*/
+STATUS SetI2cFDR (PSI2C pi2cRegs, int bitrate)
+{
+/* Constants */
+ const UINT8 div_hold[8][3] = { {9, 3}, {10, 3},
+ {12, 4}, {15, 4},
+ {5, 1}, {6, 1},
+ {7, 2}, {8, 2}
+ };
+
+ const UINT8 scl_tap[8][2] = { {4, 1}, {4, 2},
+ {6, 4}, {6, 8},
+ {14, 16}, {30, 32},
+ {62, 64}, {126, 128}
+ };
+
+ UINT8 mfdr_bits;
+
+ int i = 0;
+ int j = 0;
+
+ int Diff, min;
+ int WhichFreq, iRec, jRec;
+ int SCL_Period;
+ int SCL_Hold;
+ int I2C_Freq;
+
+ I2CCDBG (L2, ("Entering getBitRate: bitrate %d pi2cRegs 0x%08x\n",
+ bitrate, (int) pi2cRegs, 0, 0, 0, 0));
+
+ if (bitrate < 0) {
+ I2CCDBG (NO, ("Invalid bitrate\n", 0, 0, 0, 0, 0, 0));
+ return ERROR;
+ }
+
+ /* Initialize */
+ mfdr_bits = 0;
+ min = 0x7fffffff;
+ WhichFreq = iRec = jRec = 0;
+
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
+ /* SCL Period = 2 * (scl2tap + [(SCL_Tap - 1) * tap2tap] + 2)
+ * SCL Hold = scl2tap + ((SDA_Tap - 1) * tap2tap) + 3
+ * Bit Rate (I2C Freq) = System Freq / SCL Period
+ */
+ SCL_Period =
+ 2 * (scl_tap[i][0] +
+ ((div_hold[j][0] - 1) * scl_tap[i][1]) +
+ 2);
+
+ /* Now get the I2C Freq */
+ I2C_Freq = DEV_CLOCK_FREQ / SCL_Period;
+
+ /* Take equal or slower */
+ if (I2C_Freq > bitrate)
+ continue;
+
+ /* Take the differences */
+ Diff = I2C_Freq - bitrate;
+
+ Diff = ABS (Diff);
+
+ /* Find the closer value */
+ if (Diff < min) {
+ min = Diff;
+ WhichFreq = I2C_Freq;
+ iRec = i;
+ jRec = j;
+ }
+
+ I2CCDBG (L2,
+ ("--- (%d,%d) I2C_Freq %d minDiff %d min %d\n",
+ i, j, I2C_Freq, Diff, min, 0));
+ }
+ }
+
+ SCL_Period =
+ 2 * (scl_tap[iRec][0] +
+ ((div_hold[jRec][0] - 1) * scl_tap[iRec][1]) + 2);
+
+ I2CCDBG (L2, ("\nmin %d WhichFreq %d iRec %d jRec %d\n",
+ min, WhichFreq, iRec, jRec, 0, 0));
+ I2CCDBG (L2, ("--- scl2tap %d SCL_Tap %d tap2tap %d\n",
+ scl_tap[iRec][0], div_hold[jRec][0], scl_tap[iRec][1],
+ 0, 0, 0));
+
+ /* This may no require */
+ SCL_Hold =
+ scl_tap[iRec][0] +
+ ((div_hold[jRec][1] - 1) * scl_tap[iRec][1]) + 3;
+ I2CCDBG (L2,
+ ("--- SCL_Period %d SCL_Hold %d\n", SCL_Period, SCL_Hold, 0,
+ 0, 0, 0));
+
+ I2CCDBG (L2, ("--- mfdr_bits %x\n", mfdr_bits, 0, 0, 0, 0, 0));
+
+ /* FDR 4,3,2 */
+ if ((iRec & 1) == 1)
+ mfdr_bits |= 0x04; /* FDR 2 */
+ if ((iRec & 2) == 2)
+ mfdr_bits |= 0x08; /* FDR 3 */
+ if ((iRec & 4) == 4)
+ mfdr_bits |= 0x10; /* FDR 4 */
+ /* FDR 5,1,0 */
+ if ((jRec & 1) == 1)
+ mfdr_bits |= 0x01; /* FDR 0 */
+ if ((jRec & 2) == 2)
+ mfdr_bits |= 0x02; /* FDR 1 */
+ if ((jRec & 4) == 4)
+ mfdr_bits |= 0x20; /* FDR 5 */
+
+ I2CCDBG (L2, ("--- mfdr_bits %x\n", mfdr_bits, 0, 0, 0, 0, 0));
+
+ pi2cRegs->fdr = mfdr_bits;
+
+ return OK;
+}
diff --git a/arch/powerpc/cpu/mpc8220/i2cCore.h b/arch/powerpc/cpu/mpc8220/i2cCore.h
new file mode 100644
index 0000000..72783fd
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/i2cCore.h
@@ -0,0 +1,103 @@
+/*
+ * i2cCore.h
+ *
+ * Prototypes, etc. for the Motorola MPC8220
+ * embedded cpu chips
+ *
+ * 2004 (c) Freescale, Inc.
+ * Author: TsiChung Liew <Tsi-Chung.Liew@freescale.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
+ */
+#ifndef __INCi2ccoreh
+#define __INCi2ccoreh
+#ifndef __ASSEMBLY__
+/* device types */
+#define I2C_DEVICE_TYPE_EEPROM 0
+#define I2C_EEPROM_ADRS 0xa0
+#define I2C_CTRL_ADRS I2C_EEPROM_ADRS
+#define EEPROM_ADDR0 0xA2 /* on Dimm SPD eeprom */
+#define EEPROM_ADDR1 0xA4 /* on Board SPD eeprom */
+#define EEPROM_ADDR2 0xD2 /* non-standard eeprom - clock generator */
+/* Control Register */
+#define I2C_CTL_EN 0x80 /* I2C Enable */
+#define I2C_CTL_IEN 0x40 /* I2C Interrupt Enable */
+#define I2C_CTL_STA 0x20 /* Master/Slave Mode select */
+#define I2C_CTL_TX 0x10 /* Transmit/Receive Mode Select */
+#define I2C_CTL_TXAK 0x08 /* Transmit Acknowledge Enable */
+#define I2C_CTL_RSTA 0x04 /* Repeat Start */
+/* Status Register */
+#define I2C_STA_CF 0x80 /* Data Transfer */
+#define I2C_STA_AAS 0x40 /* Adressed As Slave */
+#define I2C_STA_BB 0x20 /* Bus Busy */
+#define I2C_STA_AL 0x10 /* Arbitration Lost */
+#define I2C_STA_SRW 0x04 /* Slave Read/Write */
+#define I2C_STA_IF 0x02 /* I2C Interrupt */
+#define I2C_STA_RXAK 0x01 /* Receive Acknowledge */
+/* Interrupt Contol Register */
+#define I2C_INT_BNBE2 0x80 /* Bus Not Busy Enable 2 */
+#define I2C_INT_TE2 0x40 /* Transmit Enable 2 */
+#define I2C_INT_RE2 0x20 /* Receive Enable 2 */
+#define I2C_INT_IE2 0x10 /* Interrupt Enable 2 */
+#define I2C_INT_BNBE1 0x08 /* Bus Not Busy Enable 1 */
+#define I2C_INT_TE1 0x04 /* Transmit Enable 1 */
+#define I2C_INT_RE1 0x02 /* Receive Enable 1 */
+#define I2C_INT_IE1 0x01 /* Interrupt Enable 1 */
+#define I2C_POLL_COUNT 0x100000
+#define I2C_ENABLE 0x00000001
+#define I2C_DISABLE 0x00000002
+#define I2C_START 0x00000004
+#define I2C_REPSTART 0x00000008
+#define I2C_STOP 0x00000010
+#define I2C_BITRATE 0x00000020
+#define I2C_SLAVEADR 0x00000040
+#define I2C_STARTADR 0x00000080
+#undef TWOBYTES
+typedef struct i2c_settings {
+ /* Device settings */
+ int bit_rate; /* Device bit rate */
+ u8 i2c_adr; /* I2C address */
+ u8 slv_adr; /* Slave address */
+#ifdef TWOBYTES
+ u16 str_adr; /* Start address */
+#else
+ u8 str_adr; /* Start address */
+#endif
+ int xfer_size; /* Transfer Size */
+
+ int bI2c_en; /* Enable or Disable */
+ int cmdFlag; /* I2c Command Flags */
+} i2cset_t;
+
+/*
+int check_status(PSI2C pi2c, u8 sta_bit, u8 truefalse);
+int i2c_enable(PSI2C pi2c, PI2CSET pi2cSet);
+int i2c_disable(PSI2C pi2c);
+int i2c_start(PSI2C pi2c, PI2CSET pi2cSet);
+int i2c_stop(PSI2C pi2c);
+int i2c_clear(PSI2C pi2c);
+int i2c_readblock (PSI2C pi2c, PI2CSET pi2cSet, u8 *Data);
+int i2c_writeblock (PSI2C pi2c, PI2CSET pi2cSet, u8 *Data);
+int i2c_readbyte(PSI2C pi2c, u8 *readb, int *index);
+int i2c_writebyte(PSI2C pi2c, u8 *writeb);
+int SetI2cFDR( PSI2C pi2cRegs, int bitrate );
+*/
+#endif /* __ASSEMBLY__ */
+
+#endif /* __INCi2ccoreh */
diff --git a/arch/powerpc/cpu/mpc8220/interrupts.c b/arch/powerpc/cpu/mpc8220/interrupts.c
new file mode 100644
index 0000000..78e9917
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/interrupts.c
@@ -0,0 +1,80 @@
+/*
+ * (C) Copyright -2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * interrupts.c - just enough support for the decrementer/timer
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <command.h>
+
+int interrupt_init_cpu (ulong * decrementer_count)
+{
+ *decrementer_count = get_tbclk () / CONFIG_SYS_HZ;
+
+ return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+ puts ("external_interrupt (oops!)\n");
+}
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+ /* nothing to do here */
+ return;
+}
+
+/****************************************************************************/
+
+/*
+ * Install and free a interrupt handler.
+ */
+
+void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg)
+{
+
+}
+
+void irq_free_handler (int vec)
+{
+
+}
+
+/****************************************************************************/
+
+void
+do_irqinfo (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[])
+{
+ puts ("IRQ related functions are unimplemented currently.\n");
+}
diff --git a/arch/powerpc/cpu/mpc8220/io.S b/arch/powerpc/cpu/mpc8220/io.S
new file mode 100644
index 0000000..5ecdf55
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/io.S
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ * Copyright (C) 2003 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
+ */
+
+#include <config.h>
+#include <ppc_asm.tmpl>
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in8 */
+/* Description: Input 8 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl in8
+in8:
+ lbz r3,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in16 */
+/* Description: Input 16 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl in16
+in16:
+ lhz r3,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in16r */
+/* Description: Input 16 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+ .globl in16r
+in16r:
+ lhbrx r3,0,r3
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in32 */
+/* Description: Input 32 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl in32
+in32:
+ lwz 3,0(3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in32r */
+/* Description: Input 32 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+ .globl in32r
+in32r:
+ lwbrx r3,0,r3
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out8 */
+/* Description: Output 8 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out8
+out8:
+ stb r4,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out16 */
+/* Description: Output 16 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out16
+out16:
+ sth r4,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out16r */
+/* Description: Byte reverse and output 16 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out16r
+out16r:
+ sthbrx r4,0,r3
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out32 */
+/* Description: Output 32 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out32
+out32:
+ stw r4,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out32r */
+/* Description: Byte reverse and output 32 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out32r
+out32r:
+ stwbrx r4,0,r3
+ sync
+ blr
diff --git a/arch/powerpc/cpu/mpc8220/loadtask.c b/arch/powerpc/cpu/mpc8220/loadtask.c
new file mode 100644
index 0000000..6d8b627
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/loadtask.c
@@ -0,0 +1,78 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on code
+ * (C) Copyright Motorola, Inc., 2000
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+
+/* Multichannel DMA microcode */
+extern int taskTable;
+
+void loadtask (int basetask, int tasks)
+{
+ int *sram = (int *) (MMAP_SRAM + 512);
+ int *task_org = &taskTable;
+ unsigned int start, offset, end;
+ int i;
+
+#ifdef DEBUG
+ printf ("basetask = %d, tasks = %d\n", basetask, tasks);
+ printf ("task_org = 0x%08x\n", (unsigned int) task_org);
+#endif
+
+ /* setup TaskBAR register */
+ *(vu_long *) MMAP_DMA = (MMAP_SRAM + 512);
+
+ /* relocate task table entries */
+ offset = (unsigned int) sram;
+ for (i = basetask; i < basetask + tasks; i++) {
+ sram[i * 8 + 0] = task_org[i * 8 + 0] + offset;
+ sram[i * 8 + 1] = task_org[i * 8 + 1] + offset;
+ sram[i * 8 + 2] = task_org[i * 8 + 2] + offset;
+ sram[i * 8 + 3] = task_org[i * 8 + 3] + offset;
+ sram[i * 8 + 4] = task_org[i * 8 + 4];
+ sram[i * 8 + 5] = task_org[i * 8 + 5];
+ sram[i * 8 + 6] = task_org[i * 8 + 6] + offset;
+ sram[i * 8 + 7] = task_org[i * 8 + 7];
+ }
+
+ /* relocate task descriptors */
+ start = (sram[basetask * 8] - (unsigned int) sram);
+ end = (sram[(basetask + tasks - 1) * 8 + 1] - (unsigned int) sram);
+
+#ifdef DEBUG
+ printf ("TDT start = 0x%08x, end = 0x%08x\n", start, end);
+#endif
+
+ start /= 4;
+ end /= 4;
+ for (i = start; i <= end; i++) {
+ sram[i] = task_org[i];
+ }
+
+ /* relocate variables */
+ start = (sram[basetask * 8 + 2] - (unsigned int) sram);
+ end = (sram[(basetask + tasks - 1) * 8 + 2] + 256 -
+ (unsigned int) sram);
+ start /= 4;
+ end /= 4;
+ for (i = start; i < end; i++) {
+ sram[i] = task_org[i];
+ }
+
+ /* relocate function decriptors */
+ start = ((sram[basetask * 8 + 3] & 0xfffffffc) - (unsigned int) sram);
+ end = ((sram[(basetask + tasks - 1) * 8 + 3] & 0xfffffffc) + 256 -
+ (unsigned int) sram);
+ start /= 4;
+ end /= 4;
+ for (i = start; i < end; i++) {
+ sram[i] = task_org[i];
+ }
+
+ asm volatile ("sync");
+}
diff --git a/arch/powerpc/cpu/mpc8220/pci.c b/arch/powerpc/cpu/mpc8220/pci.c
new file mode 100644
index 0000000..7ef43b7
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/pci.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * Copyright (C) 2003 Motorola Inc.
+ * Xianghua Xiao (x.xiao@motorola.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
+ */
+
+/*
+ * PCI Configuration space access support for MPC8220 PCI Bridge
+ */
+#include <common.h>
+#include <mpc8220.h>
+#include <pci.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_PCI)
+
+/* System RAM mapped over PCI */
+#define CONFIG_PCI_SYS_MEM_BUS CONFIG_SYS_SDRAM_BASE
+#define CONFIG_PCI_SYS_MEM_PHYS CONFIG_SYS_SDRAM_BASE
+#define CONFIG_PCI_SYS_MEM_SIZE (1024 * 1024 * 1024)
+
+#define cfg_read(val, addr, type, op) *val = op((type)(addr));
+#define cfg_write(val, addr, type, op) op((type *)(addr), (val));
+
+#define PCI_OP(rw, size, type, op, mask) \
+int mpc8220_pci_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 addr = 0; \
+ u16 cfg_type = 0; \
+ addr = ((offset & 0xfc) | cfg_type | (dev) | 0x80000000); \
+ out_be32(hose->cfg_addr, addr); \
+ __asm__ __volatile__("sync"); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ out_be32(hose->cfg_addr, addr & 0x7fffffff); \
+ __asm__ __volatile__("sync"); \
+ return 0; \
+}
+
+PCI_OP(read, byte, u8 *, in_8, 3)
+PCI_OP(read, word, u16 *, in_le16, 2)
+PCI_OP(write, byte, u8, out_8, 3)
+PCI_OP(write, word, u16, out_le16, 2)
+PCI_OP(write, dword, u32, out_le32, 0)
+
+int mpc8220_pci_read_config_dword(struct pci_controller *hose, pci_dev_t dev,
+ int offset, u32 *val)
+{
+ u32 addr;
+ u32 tmpv;
+ u32 mask = 2; /* word access */
+ /* Read lower 16 bits */
+ addr = ((offset & 0xfc) | (dev) | 0x80000000);
+ out_be32(hose->cfg_addr, addr);
+ __asm__ __volatile__("sync");
+ *val = (u32) in_le16((u16 *) (hose->cfg_data + (offset & mask)));
+ out_be32(hose->cfg_addr, addr & 0x7fffffff);
+ __asm__ __volatile__("sync");
+
+ /* Read upper 16 bits */
+ offset += 2;
+ addr = ((offset & 0xfc) | 1 | (dev) | 0x80000000);
+ out_be32(hose->cfg_addr, addr);
+ __asm__ __volatile__("sync");
+ tmpv = (u32) in_le16((u16 *) (hose->cfg_data + (offset & mask)));
+ out_be32(hose->cfg_addr, addr & 0x7fffffff);
+ __asm__ __volatile__("sync");
+
+ /* combine results into dword value */
+ *val = (tmpv << 16) | *val;
+
+ return 0;
+}
+
+void
+pci_mpc8220_init(struct pci_controller *hose)
+{
+ u32 win0, win1, win2;
+ volatile mpc8220_xcpci_t *xcpci =
+ (volatile mpc8220_xcpci_t *) MMAP_XCPCI;
+
+ volatile pcfg8220_t *portcfg = (volatile pcfg8220_t *) MMAP_PCFG;
+
+ win0 = (u32) CONFIG_PCI_MEM_PHYS;
+ win1 = (u32) CONFIG_PCI_IO_PHYS;
+ win2 = (u32) CONFIG_PCI_CFG_PHYS;
+
+ /* Assert PCI reset */
+ out_be32 (&xcpci->glb_stat_ctl, PCI_GLB_STAT_CTRL_PR);
+
+ /* Disable prefetching but read-multiples will still prefetch */
+ out_be32 (&xcpci->target_ctrl, 0x00000000);
+
+ /* Initiator windows */
+ out_be32 (&xcpci->init_win0, (win0 >> 16) | win0 | 0x003f0000);
+ out_be32 (&xcpci->init_win1, ((win1 >> 16) | win1 ));
+ out_be32 (&xcpci->init_win2, ((win2 >> 16) | win2 ));
+
+ out_be32 (&xcpci->init_win_cfg,
+ PCI_INIT_WIN_CFG_WIN0_CTRL_EN |
+ PCI_INIT_WIN_CFG_WIN1_CTRL_EN | PCI_INIT_WIN_CFG_WIN1_CTRL_IO |
+ PCI_INIT_WIN_CFG_WIN2_CTRL_EN | PCI_INIT_WIN_CFG_WIN2_CTRL_IO);
+
+ out_be32 (&xcpci->init_ctrl, 0x00000000);
+
+ /* Enable bus master and mem access */
+ out_be32 (&xcpci->stat_cmd_reg, PCI_STAT_CMD_B | PCI_STAT_CMD_M);
+
+ /* Cache line size and master latency */
+ out_be32 (&xcpci->bist_htyp_lat_cshl, (0xf8 << PCI_CFG1_LT_SHIFT));
+
+ out_be32 (&xcpci->base0, PCI_BASE_ADDR_REG0); /* 256MB - MBAR space */
+ out_be32 (&xcpci->base1, PCI_BASE_ADDR_REG1); /* 1GB - SDRAM space */
+
+ out_be32 (&xcpci->target_bar0,
+ PCI_TARGET_BASE_ADDR_REG0 | PCI_TARGET_BASE_ADDR_EN);
+ out_be32 (&xcpci->target_bar1,
+ PCI_TARGET_BASE_ADDR_REG1 | PCI_TARGET_BASE_ADDR_EN);
+
+ /* Deassert reset bit */
+ out_be32 (&xcpci->glb_stat_ctl, 0x00000000);
+
+ /* Enable PCI bus master support */
+ /* Set PCIGNT1, PCIREQ1, PCIREQ0/PCIGNTIN, PCIGNT0/PCIREQOUT,
+ PCIREQ2, PCIGNT2 */
+ out_be32((volatile u32 *)&portcfg->pcfg3,
+ (in_be32((volatile u32 *)&portcfg->pcfg3) & 0xFC3FCE7F));
+ out_be32((volatile u32 *)&portcfg->pcfg3,
+ (in_be32((volatile u32 *)&portcfg->pcfg3) | 0x01400180));
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ pci_set_region(hose->regions + 0,
+ CONFIG_PCI_MEM_BUS,
+ CONFIG_PCI_MEM_PHYS,
+ CONFIG_PCI_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ pci_set_region(hose->regions + 1,
+ CONFIG_PCI_IO_BUS,
+ CONFIG_PCI_IO_PHYS,
+ CONFIG_PCI_IO_SIZE,
+ PCI_REGION_IO);
+
+ pci_set_region(hose->regions + 2,
+ CONFIG_PCI_SYS_MEM_BUS,
+ CONFIG_PCI_SYS_MEM_PHYS,
+ CONFIG_PCI_SYS_MEM_SIZE,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ hose->region_count = 3;
+
+ hose->cfg_addr = &(xcpci->cfg_adr);
+ hose->cfg_data = (volatile unsigned char *)CONFIG_PCI_CFG_BUS;
+
+ pci_set_ops(hose,
+ mpc8220_pci_read_config_byte,
+ mpc8220_pci_read_config_word,
+ mpc8220_pci_read_config_dword,
+ mpc8220_pci_write_config_byte,
+ mpc8220_pci_write_config_word,
+ mpc8220_pci_write_config_dword);
+
+ /* Hose scan */
+ pci_register_hose(hose);
+ hose->last_busno = pci_hose_scan(hose);
+
+ out_be32 (&xcpci->base0, PCI_BASE_ADDR_REG0); /* 256MB - MBAR space */
+ out_be32 (&xcpci->base1, PCI_BASE_ADDR_REG1); /* 1GB - SDRAM space */
+}
+
+#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/cpu/mpc8220/speed.c b/arch/powerpc/cpu/mpc8220/speed.c
new file mode 100644
index 0000000..62ac845
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/speed.c
@@ -0,0 +1,123 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+typedef struct pllmultiplier {
+ u8 hid1;
+ int multi;
+ int vco_div;
+} pllcfg_t;
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ *
+ */
+
+int get_clocks (void)
+{
+ pllcfg_t bus2core[] = {
+ {0x02, 2, 8}, /* 1 */
+ {0x01, 2, 4},
+ {0x0C, 3, 8}, /* 1.5 */
+ {0x00, 3, 4},
+ {0x18, 3, 2},
+ {0x05, 4, 4}, /* 2 */
+ {0x04, 4, 2},
+ {0x11, 5, 4}, /* 2.5 */
+ {0x06, 5, 2},
+ {0x10, 6, 4}, /* 3 */
+ {0x08, 6, 2},
+ {0x0E, 7, 2}, /* 3.5 */
+ {0x0A, 8, 2}, /* 4 */
+ {0x07, 9, 2}, /* 4.5 */
+ {0x0B, 10, 2}, /* 5 */
+ {0x09, 11, 2}, /* 5.5 */
+ {0x0D, 12, 2}, /* 6 */
+ {0x12, 13, 2}, /* 6.5 */
+ {0x14, 14, 2}, /* 7 */
+ {0x16, 15, 2}, /* 7.5 */
+ {0x1C, 16, 2} /* 8 */
+ };
+ u32 hid1;
+ int i, size, pci2bus;
+
+#if !defined(CONFIG_SYS_MPC8220_CLKIN)
+#error clock measuring not implemented yet - define CONFIG_SYS_MPC8220_CLKIN
+#endif
+
+ gd->inp_clk = CONFIG_SYS_MPC8220_CLKIN;
+
+ /* Read XLB to PCI(INP) clock multiplier */
+ pci2bus = (*((volatile u32 *)PCI_REG_PCIGSCR) &
+ PCI_REG_PCIGSCR_PCI2XLB_CLK_MASK)>>PCI_REG_PCIGSCR_PCI2XLB_CLK_BIT;
+
+ /* XLB bus clock */
+ gd->bus_clk = CONFIG_SYS_MPC8220_CLKIN * pci2bus;
+
+ /* PCI clock is same as input clock */
+ gd->pci_clk = CONFIG_SYS_MPC8220_CLKIN;
+
+ /* FlexBus is temporary set as the same as input clock */
+ /* will do dynamic in the future */
+ gd->flb_clk = CONFIG_SYS_MPC8220_CLKIN;
+
+ /* CPU Clock - Read HID1 */
+ asm volatile ("mfspr %0, 1009":"=r" (hid1):);
+
+ size = sizeof (bus2core) / sizeof (pllcfg_t);
+
+ hid1 >>= 27;
+
+ for (i = 0; i < size; i++)
+ if (hid1 == bus2core[i].hid1) {
+ gd->cpu_clk = (bus2core[i].multi * gd->bus_clk) >> 1;
+ gd->vco_clk = CONFIG_SYS_MPC8220_SYSPLL_VCO_MULTIPLIER * (gd->pci_clk * bus2core[i].vco_div)/2;
+ break;
+ }
+
+ /* hardcoded 81MHz for now */
+ gd->pev_clk = 81000000;
+
+ return (0);
+}
+
+int prt_mpc8220_clks (void)
+{
+ char buf1[32], buf2[32], buf3[32], buf4[32];
+
+ printf (" Bus %s MHz, CPU %s MHz, PCI %s MHz, VCO %s MHz\n",
+ strmhz(buf1, gd->bus_clk),
+ strmhz(buf2, gd->cpu_clk),
+ strmhz(buf3, gd->pci_clk),
+ strmhz(buf4, gd->vco_clk)
+ );
+ return (0);
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/arch/powerpc/cpu/mpc8220/start.S b/arch/powerpc/cpu/mpc8220/start.S
new file mode 100644
index 0000000..3d79d8e
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/start.S
@@ -0,0 +1,750 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000 - 2003 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 MPC8220 CPUs
+ */
+#include <config.h>
+#include <mpc8220.h>
+#include <timestamp.h>
+#include <version.h>
+
+#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
+/* Floating Point enable, Machine Check and Recoverable Interr. */
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+
+/*
+ * Version string
+ */
+ .data
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION
+ .ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")"
+ .ascii CONFIG_IDENT_STRING, "\0"
+
+/*
+ * Exception vectors
+ */
+ .text
+ . = EXC_OFF_SYS_RESET
+ .globl _start
+_start:
+ li r21, BOOTFLAG_COLD /* Normal Power-On */
+ nop
+ 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:
+ mfmsr r5 /* save msr contents */
+
+ /* replace default MBAR base address from 0x80000000
+ to 0xf0000000 */
+
+#if defined(CONFIG_SYS_DEFAULT_MBAR) && !defined(CONFIG_SYS_RAMBOOT)
+ lis r3, CONFIG_SYS_MBAR@h
+ ori r3, r3, CONFIG_SYS_MBAR@l
+
+ /* MBAR is mirrored into the MBAR SPR */
+ mtspr MBAR,r3
+ mtspr SPRN_SPRG7W,r3
+ lis r4, CONFIG_SYS_DEFAULT_MBAR@h
+ stw r3, 0(r4)
+#endif /* CONFIG_SYS_DEFAULT_MBAR */
+
+ /* Initialise the MPC8220 processor core */
+ /*--------------------------------------------------------------*/
+
+ bl init_8220_core
+
+ /* initialize some things that are hard to access from C */
+ /*--------------------------------------------------------------*/
+
+ /* set up stack in on-chip SRAM */
+ lis r3, CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r3, r3, CONFIG_SYS_INIT_RAM_ADDR@l
+ ori r1, r3, CONFIG_SYS_INIT_SP_OFFSET
+
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ /* let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable ! */
+ /*--------------------------------------------------------------*/
+
+ GET_GOT /* initialize GOT access */
+
+ /* r3: IMMR */
+ bl cpu_init_f /* run low-level CPU init code (in Flash)*/
+
+ mr r3, r21
+ /* r3: BOOTFLAG */
+ bl board_init_f /* run 1st part of board init code (in Flash)*/
+
+/*
+ * Vector Table
+ */
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+ STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+ STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+#ifdef DEBUG
+ . = 0x1300
+ /*
+ * This exception occurs when the program counter matches the
+ * Instruction Address Breakpoint Register (IABR).
+ *
+ * I want the cpu to halt if this occurs so I can hunt around
+ * with the debugger and look at things.
+ *
+ * When DEBUG is defined, both machine check enable (in the MSR)
+ * and checkstop reset enable (in the reset mode register) are
+ * turned off and so a checkstop condition will result in the cpu
+ * halting.
+ *
+ * I force the cpu into a checkstop condition by putting an illegal
+ * instruction here (at least this is the theory).
+ *
+ * well - that didnt work, so just do an infinite loop!
+ */
+1: b 1b
+#else
+ STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
+#endif
+ STD_EXCEPTION(0x1400, SMI, UnknownException)
+
+ STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+ STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+ STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+ STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+ STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+ STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+ STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+ STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+ STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+ STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+ STD_EXCEPTION(0x2000, Trap_20, UnknownException)
+ STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+ STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+ STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+ STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+ STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+ STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+ STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+ STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+ STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+ STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+ STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+ STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+ STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+ STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+ STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+ . = 0x3000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+/*
+ * This code initialises the MPC8220 processor core
+ * (conforms to PowerPC 603e spec)
+ * Note: expects original MSR contents to be in r5.
+ */
+
+ .globl init_8220_core
+init_8220_core:
+
+ /* Initialize machine status; enable machine check interrupt */
+ /*--------------------------------------------------------------*/
+
+ li r3, MSR_KERNEL /* Set ME and RI flags */
+ rlwimi r3, r5, 0, 25, 25 /* preserve IP bit set by HRCW */
+#ifdef DEBUG
+ rlwimi r3, r5, 0, 21, 22 /* debugger might set SE & BE bits */
+#endif
+ SYNC /* Some chip revs need this... */
+ mtmsr r3
+ SYNC
+ mtspr SRR1, r3 /* Make SRR1 match MSR */
+
+ /* Initialize the Hardware Implementation-dependent Registers */
+ /* HID0 also contains cache control */
+ /*--------------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_HID0_INIT@h
+ ori r3, r3, CONFIG_SYS_HID0_INIT@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CONFIG_SYS_HID0_FINAL@h
+ ori r3, r3, CONFIG_SYS_HID0_FINAL@l
+ SYNC
+ mtspr HID0, r3
+
+ /* Enable Extra BATs */
+ mfspr r3, 1011 /* HID2 */
+ lis r4, 0x0004
+ ori r4, r4, 0x0000
+ or r4, r4, r3
+ mtspr 1011, r4
+ sync
+
+ /* clear all BAT's */
+ /*--------------------------------------------------------------*/
+
+ li r0, 0
+ mtspr DBAT0U, r0
+ mtspr DBAT0L, r0
+ mtspr DBAT1U, r0
+ mtspr DBAT1L, r0
+ mtspr DBAT2U, r0
+ mtspr DBAT2L, r0
+ mtspr DBAT3U, r0
+ mtspr DBAT3L, r0
+ mtspr DBAT4U, r0
+ mtspr DBAT4L, r0
+ mtspr DBAT5U, r0
+ mtspr DBAT5L, r0
+ mtspr DBAT6U, r0
+ mtspr DBAT6L, r0
+ mtspr DBAT7U, r0
+ mtspr DBAT7L, r0
+ mtspr IBAT0U, r0
+ mtspr IBAT0L, r0
+ mtspr IBAT1U, r0
+ mtspr IBAT1L, r0
+ mtspr IBAT2U, r0
+ mtspr IBAT2L, r0
+ mtspr IBAT3U, r0
+ mtspr IBAT3L, r0
+ mtspr IBAT4U, r0
+ mtspr IBAT4L, r0
+ mtspr IBAT5U, r0
+ mtspr IBAT5L, r0
+ mtspr IBAT6U, r0
+ mtspr IBAT6L, r0
+ mtspr IBAT7U, r0
+ mtspr IBAT7L, r0
+ SYNC
+
+ /* invalidate all tlb's */
+ /* */
+ /* From the 603e User Manual: "The 603e provides the ability to */
+ /* invalidate a TLB entry. The TLB Invalidate Entry (tlbie) */
+ /* instruction invalidates the TLB entry indexed by the EA, and */
+ /* operates on both the instruction and data TLBs simultaneously*/
+ /* invalidating four TLB entries (both sets in each TLB). The */
+ /* index corresponds to bits 15-19 of the EA. To invalidate all */
+ /* entries within both TLBs, 32 tlbie instructions should be */
+ /* issued, incrementing this field by one each time." */
+ /* */
+ /* "Note that the tlbia instruction is not implemented on the */
+ /* 603e." */
+ /* */
+ /* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000 */
+ /* incrementing by 0x1000 each time. The code below is sort of */
+ /* based on code in "flush_tlbs" from arch/powerpc/kernel/head.S */
+ /* */
+ /*--------------------------------------------------------------*/
+
+ li r3, 32
+ mtctr r3
+ li r3, 0
+1: tlbie r3
+ addi r3, r3, 0x1000
+ bdnz 1b
+ SYNC
+
+ /* Done! */
+ /*--------------------------------------------------------------*/
+
+ blr
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+ .globl icache_enable
+icache_enable:
+ lis r4, 0
+ ori r4, r4, CONFIG_SYS_HID0_INIT /* set ICE & ICFI bit */
+ rlwinm r3, r4, 0, 21, 19 /* clear the ICFI bit */
+
+ /*
+ * The setting of the instruction cache enable (ICE) bit must be
+ * preceded by an isync instruction to prevent the cache from being
+ * enabled or disabled while an instruction access is in progress.
+ */
+ isync
+ mtspr HID0, r4 /* Enable Instr Cache & Inval cache */
+ mtspr HID0, r3 /* using 2 consec instructions */
+ isync
+ blr
+
+ .globl icache_disable
+icache_disable:
+ mfspr r3, HID0
+ rlwinm r3, r3, 0, 17, 15 /* clear the ICE bit */
+ mtspr HID0, r3
+ isync
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, HID0_ICE_BITPOS + 1, 31, 31
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+ lis r4, 0
+ ori r4, r4, HID0_DCE|HID0_DCFI /* set DCE & DCFI bit */
+ rlwinm r3, r4, 0, 22, 20 /* clear the DCFI bit */
+
+ /* Enable address translation in MSR bit */
+ mfmsr r5
+ ori r5, r5, 0x
+
+
+ /*
+ * The setting of the instruction cache enable (ICE) bit must be
+ * preceded by an isync instruction to prevent the cache from being
+ * enabled or disabled while an instruction access is in progress.
+ */
+ isync
+ mtspr HID0, r4 /* Enable Data Cache & Inval cache*/
+ mtspr HID0, r3 /* using 2 consec instructions */
+ isync
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mfspr r3, HID0
+ rlwinm r3, r3, 0, 18, 16 /* clear the DCE bit */
+ mtspr HID0, r3
+ isync
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, HID0_DCE_BITPOS + 1, 31, 31
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Global Data pointer */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mfspr r7,HID0 /* don't do dcbst if dcache is disabled */
+ rlwinm r7,r7,HID0_DCE_BITPOS+1,31,31
+ cmpwi r7,0
+ beq 9f
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+9: mfspr r7,HID0 /* don't do icbi if icache is disabled */
+ rlwinm r7,r7,HID0_ICE_BITPOS+1,31,31
+ cmpwi r7,0
+ beq 7f
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ 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
+
+ mfmsr r3 /* now that the vectors have */
+ lis r7, MSR_IP@h /* relocated into low memory */
+ ori r7, r7, MSR_IP@l /* MSR[IP] can be turned off */
+ andc r3, r3, r7 /* (if it was on) */
+ SYNC /* Some chip revs need this... */
+ mtmsr r3
+ SYNC
+
+ mtlr r4 /* restore link register */
+ blr
diff --git a/arch/powerpc/cpu/mpc8220/traps.c b/arch/powerpc/cpu/mpc8220/traps.c
new file mode 100644
index 0000000..13894c9
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/traps.c
@@ -0,0 +1,236 @@
+/*
+ * 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)
+ * fixed Machine Check Reasons by Reinhard Meyer (r.meyer@emk-elektronik.de)
+ *
+ * (C) Copyright 2000-2003
+ * 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>
+
+/* 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);
+ /* refer to 603e Manual (MPC603EUM/AD), chapter 4.5.2.1 */
+ 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);
+}
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint (struct pt_regs *);
+#endif
+
+void DebugException (struct pt_regs *regs)
+{
+
+ printf ("Debugger trap at @ %lx\n", regs->nip);
+ show_regs (regs);
+#if defined(CONFIG_CMD_BEDBUG)
+ do_bedbug_breakpoint (regs);
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int addr_probe (uint * addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__ ("1: lwz %0,0(%1)\n"
+ " eieio\n"
+ " li %0,0\n"
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ "3: li %0,-1\n"
+ " b 2b\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 2\n"
+ " .long 1b,3b\n"
+ ".text":"=r" (retval):"r" (addr));
+
+ return (retval);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8220/u-boot.lds b/arch/powerpc/cpu/mpc8220/u-boot.lds
new file mode 100644
index 0000000..31a7a0e
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/u-boot.lds
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2003-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
+ */
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : { *(.init) }
+ .plt : { *(.plt) }
+ .text :
+ {
+ arch/powerpc/cpu/mpc8220/start.o (.text)
+ *(.text)
+ *(.got1)
+ . = ALIGN(16);
+ *(.eh_frame)
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ *(.got)
+ _GOT2_TABLE_ = .;
+ *(.got2)
+ _FIXUP_TABLE_ = .;
+ *(.fixup)
+ }
+ __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.dynamic)
+ CONSTRUCTORS
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+ __u_boot_cmd_start = .;
+ .u_boot_cmd : { *(.u_boot_cmd) }
+ __u_boot_cmd_end = .;
+
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(4);
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}
diff --git a/arch/powerpc/cpu/mpc8220/uart.c b/arch/powerpc/cpu/mpc8220/uart.c
new file mode 100644
index 0000000..0c4b536
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8220/uart.c
@@ -0,0 +1,126 @@
+/*
+ * (C) Copyright 2004, Freescale, Inc
+ * TsiChung Liew, Tsi-Chung.Liew@freescale.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
+ *
+ */
+
+/*
+ * Minimal serial functions needed to use one of the PSC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <mpc8220.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PSC_BASE MMAP_PSC1
+
+#if defined(CONFIG_PSC_CONSOLE)
+int serial_init (void)
+{
+ volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+ u32 counter;
+
+ /* write to SICR: SIM2 = uart mode,dcd does not affect rx */
+ psc->cr = 0;
+ psc->ipcr_acr = 0;
+ psc->isr_imr = 0;
+
+ /* write to CSR: RX/TX baud rate from timers */
+ psc->sr_csr = 0xdd000000;
+
+ psc->mr1_2 = PSC_MR1_BITS_CHAR_8 | PSC_MR1_NO_PARITY | PSC_MR2_STOP_BITS_1;
+
+ /* Setting up BaudRate */
+ counter = ((gd->bus_clk / gd->baudrate)) >> 5;
+ counter++;
+
+ /* write to CTUR: divide counter upper byte */
+ psc->ctur = ((counter & 0xff00) << 16);
+ /* write to CTLR: divide counter lower byte */
+ psc->ctlr = ((counter & 0x00ff) << 24);
+
+ psc->cr = PSC_CR_RST_RX_CMD;
+ psc->cr = PSC_CR_RST_TX_CMD;
+ psc->cr = PSC_CR_RST_ERR_STS_CMD;
+ psc->cr = PSC_CR_RST_BRK_INT_CMD;
+ psc->cr = PSC_CR_RST_MR_PTR_CMD;
+
+ psc->cr = PSC_CR_RX_ENABLE | PSC_CR_TX_ENABLE;
+ return (0);
+}
+
+void serial_putc (const char c)
+{
+ volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+
+ if (c == '\n')
+ serial_putc ('\r');
+
+ /* Wait for last character to go. */
+ while (!(psc->sr_csr & PSC_SR_TXRDY));
+
+ psc->xmitbuf[0] = c;
+}
+
+void serial_puts (const char *s)
+{
+ while (*s) {
+ serial_putc (*s++);
+ }
+}
+
+int serial_getc (void)
+{
+ volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+
+ /* Wait for a character to arrive. */
+ while (!(psc->sr_csr & PSC_SR_RXRDY));
+ return psc->xmitbuf[2];
+}
+
+int serial_tstc (void)
+{
+ volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+
+ return (psc->sr_csr & PSC_SR_RXRDY);
+}
+
+void serial_setbrg (void)
+{
+ volatile psc8220_t *psc = (psc8220_t *) PSC_BASE;
+ u32 counter;
+
+ counter = ((gd->bus_clk / gd->baudrate)) >> 5;
+ counter++;
+
+ /* write to CTUR: divide counter upper byte */
+ psc->ctur = ((counter & 0xff00) << 16);
+ /* write to CTLR: divide counter lower byte */
+ psc->ctlr = ((counter & 0x00ff) << 24);
+
+ psc->cr = PSC_CR_RST_RX_CMD;
+ psc->cr = PSC_CR_RST_TX_CMD;
+
+ psc->cr = PSC_CR_RX_ENABLE | PSC_CR_TX_ENABLE;
+}
+#endif /* CONFIG_PSC_CONSOLE */