summaryrefslogtreecommitdiff
path: root/cpu/mpc824x
diff options
context:
space:
mode:
authorwdenk <wdenk>2002-11-03 00:24:07 +0000
committerwdenk <wdenk>2002-11-03 00:24:07 +0000
commitc609719b8d1b2dca590e0ed499016d041203e403 (patch)
tree7ea1755d80903ff972f312a249eb856061d40e15 /cpu/mpc824x
parent5b1d713721c3ea02549940133f09236783dda1f9 (diff)
downloadu-boot-imx-c609719b8d1b2dca590e0ed499016d041203e403.zip
u-boot-imx-c609719b8d1b2dca590e0ed499016d041203e403.tar.gz
u-boot-imx-c609719b8d1b2dca590e0ed499016d041203e403.tar.bz2
Initial revision
Diffstat (limited to 'cpu/mpc824x')
-rw-r--r--cpu/mpc824x/cpu_init.c383
-rw-r--r--cpu/mpc824x/drivers/i2c/i2c1.c1228
-rw-r--r--cpu/mpc824x/pci.c78
-rw-r--r--cpu/mpc824x/start.S835
4 files changed, 2524 insertions, 0 deletions
diff --git a/cpu/mpc824x/cpu_init.c b/cpu/mpc824x/cpu_init.c
new file mode 100644
index 0000000..602f65d
--- /dev/null
+++ b/cpu/mpc824x/cpu_init.c
@@ -0,0 +1,383 @@
+/*
+ * (C) Copyright 2000
+ * Rob Taylor. Flying Pig Systems. robt@flyingpig.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 <asm/processor.h>
+#include <mpc824x.h>
+
+#ifndef CFG_BANK0_ROW
+#define CFG_BANK0_ROW 0
+#endif
+#ifndef CFG_BANK1_ROW
+#define CFG_BANK1_ROW 0
+#endif
+#ifndef CFG_BANK2_ROW
+#define CFG_BANK2_ROW 0
+#endif
+#ifndef CFG_BANK3_ROW
+#define CFG_BANK3_ROW 0
+#endif
+#ifndef CFG_BANK4_ROW
+#define CFG_BANK4_ROW 0
+#endif
+#ifndef CFG_BANK5_ROW
+#define CFG_BANK5_ROW 0
+#endif
+#ifndef CFG_BANK6_ROW
+#define CFG_BANK6_ROW 0
+#endif
+#ifndef CFG_BANK7_ROW
+#define CFG_BANK7_ROW 0
+#endif
+#ifndef CFG_DBUS_SIZE2
+#define CFG_DBUS_SIZE2 0
+#endif
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ */
+void
+cpu_init_f (void)
+{
+/* MOUSSE board is initialized in asm */
+#if !defined(CONFIG_MOUSSE) && !defined(CONFIG_BMW)
+ register unsigned long val;
+ CONFIG_WRITE_HALFWORD(PCICR, 0x06); /* Bus Master, respond to PCI memory space acesses*/
+/* CONFIG_WRITE_HALFWORD(PCISR, 0xffff); */ /*reset PCISR*/
+
+#if defined(CONFIG_MUSENKI) || defined(CONFIG_PN62)
+/* Why is this here, you ask? Try, just try setting 0x8000
+ * in PCIACR with CONFIG_WRITE_HALFWORD()
+ * this one was a stumper, and we are annoyed
+ */
+
+#define M_CONFIG_WRITE_HALFWORD( addr, data ) \
+ __asm__ __volatile__( \
+ " \
+ stw %2,0(%0)\n \
+ sync\n \
+ sth %3,2(%1)\n \
+ sync\n \
+ " \
+ : /* no output */ \
+ : "r" (CONFIG_ADDR), "r" (CONFIG_DATA), \
+ "r" (PCISWAP(addr & ~3)), "r" (PCISWAP(data << 16)) \
+ );
+
+ M_CONFIG_WRITE_HALFWORD(PCIACR, 0x8000);
+#endif
+
+ CONFIG_WRITE_BYTE(PCLSR, 0x8); /* set PCI cache line size */
+
+ /*
+ * Note that although this bit is cleared after a hard reset, it
+ * must be explicitly set and then cleared by software during
+ * initialization in order to guarantee correct operation of the
+ * DLL and the SDRAM_CLK[0:3] signals (if they are used).
+ */
+ CONFIG_READ_BYTE (AMBOR, val);
+ CONFIG_WRITE_BYTE(AMBOR, val & 0xDF);
+ CONFIG_WRITE_BYTE(AMBOR, val | 0x20);
+ CONFIG_WRITE_BYTE(AMBOR, val & 0xDF);
+
+ CONFIG_READ_WORD(PICR1, val);
+#if defined(CONFIG_MPC8240)
+ CONFIG_WRITE_WORD( PICR1,
+ (val & (PICR1_ADDRESS_MAP | PICR1_RCS0)) |
+ PIRC1_MSK | PICR1_PROC_TYPE_603E |
+ PICR1_FLASH_WR_EN | PICR1_MCP_EN |
+ PICR1_CF_DPARK | PICR1_EN_PCS |
+ PICR1_CF_APARK );
+#elif defined(CONFIG_MPC8245)
+ CONFIG_WRITE_WORD( PICR1,
+ (val & (PICR1_RCS0)) |
+ PICR1_PROC_TYPE_603E |
+ PICR1_FLASH_WR_EN | PICR1_MCP_EN |
+ PICR1_CF_DPARK | PICR1_NO_BUSW_CK |
+ PICR1_DEC| PICR1_CF_APARK | 0x10); /* 8245 UM says bit 4 must be set */
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+
+ CONFIG_READ_WORD(PICR2, val);
+ val= val & ~ (PICR2_CF_SNOOP_WS_MASK | PICR2_CF_APHASE_WS_MASK); /*mask off waitstate bits*/
+#ifndef CONFIG_PN62
+ val |= PICR2_CF_SNOOP_WS_1WS | PICR2_CF_APHASE_WS_1WS; /*1 wait state*/
+#endif
+ CONFIG_WRITE_WORD(PICR2, val);
+
+ CONFIG_WRITE_WORD(EUMBBAR, CFG_EUMB_ADDR);
+#ifndef CFG_RAMBOOT
+ CONFIG_WRITE_WORD(MCCR1, (CFG_ROMNAL << MCCR1_ROMNAL_SHIFT) |
+ (CFG_BANK0_ROW) |
+ (CFG_BANK1_ROW << MCCR1_BANK1ROW_SHIFT) |
+ (CFG_BANK2_ROW << MCCR1_BANK2ROW_SHIFT) |
+ (CFG_BANK3_ROW << MCCR1_BANK3ROW_SHIFT) |
+ (CFG_BANK4_ROW << MCCR1_BANK4ROW_SHIFT) |
+ (CFG_BANK5_ROW << MCCR1_BANK5ROW_SHIFT) |
+ (CFG_BANK6_ROW << MCCR1_BANK6ROW_SHIFT) |
+ (CFG_BANK7_ROW << MCCR1_BANK7ROW_SHIFT) |
+ (CFG_ROMFAL << MCCR1_ROMFAL_SHIFT));
+#endif
+
+#if defined(CFG_ASRISE) && defined(CFG_ASFALL)
+ CONFIG_WRITE_WORD(MCCR2, CFG_REFINT << MCCR2_REFINT_SHIFT |
+ CFG_ASRISE << MCCR2_ASRISE_SHIFT |
+ CFG_ASFALL << MCCR2_ASFALL_SHIFT);
+#else
+ CONFIG_WRITE_WORD(MCCR2, CFG_REFINT << MCCR2_REFINT_SHIFT);
+#endif
+
+#if defined(CONFIG_MPC8240)
+ CONFIG_WRITE_WORD(MCCR3,
+ (((CFG_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) |
+ (CFG_REFREC << MCCR3_REFREC_SHIFT) |
+ (CFG_RDLAT << MCCR3_RDLAT_SHIFT));
+#elif defined(CONFIG_MPC8245)
+ CONFIG_WRITE_WORD(MCCR3,
+ (((CFG_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) |
+ (CFG_REFREC << MCCR3_REFREC_SHIFT));
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+
+/* this is gross. We think these should all be the same, and various boards
+ * should define CFG_ACTORW to 0 if they don't want to set it, or even, if
+ * its not set, we define it to zero in this file
+ */
+#if defined(CONFIG_CU824) || defined(CONFIG_PN62)
+ CONFIG_WRITE_WORD(MCCR4,
+ (CFG_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+ (CFG_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+ MCCR4_BIT21 |
+ (CFG_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+ ((CFG_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+ (((CFG_SDMODE_CAS_LAT <<4) | (CFG_SDMODE_WRAP <<3) |
+ CFG_SDMODE_BURSTLEN) << MCCR4_SDMODE_SHIFT) |
+ (CFG_ACTORW << MCCR4_ACTTORW_SHIFT) |
+ (((CFG_BSTOPRE & 0x03c0) >> 6) << MCCR4_BSTOPRE6TO9_SHIFT));
+#elif defined(CONFIG_MPC8240)
+ CONFIG_WRITE_WORD(MCCR4,
+ (CFG_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+ (CFG_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+ MCCR4_BIT21 |
+ (CFG_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+ ((CFG_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+ (((CFG_SDMODE_CAS_LAT <<4) | (CFG_SDMODE_WRAP <<3) |
+ (CFG_SDMODE_BURSTLEN)) <<MCCR4_SDMODE_SHIFT) |
+ (((CFG_BSTOPRE & 0x03c0) >> 6) <<MCCR4_BSTOPRE6TO9_SHIFT ));
+#elif defined(CONFIG_MPC8245)
+ CONFIG_READ_WORD(MCCR1, val);
+ val &= MCCR1_DBUS_SIZE0; /* test for 64-bit mem bus */
+
+ CONFIG_WRITE_WORD(MCCR4,
+ (CFG_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+ (CFG_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+ (CFG_EXTROM ? MCCR4_EXTROM : 0) |
+ (CFG_REGDIMM ? MCCR4_REGDIMM : 0) |
+ (CFG_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+ ((CFG_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+ (CFG_DBUS_SIZE2 << MCCR4_DBUS_SIZE2_SHIFT) |
+ (((CFG_SDMODE_CAS_LAT <<4) | (CFG_SDMODE_WRAP <<3) |
+ (val ? 2 : 3)) << MCCR4_SDMODE_SHIFT) |
+ (CFG_ACTORW << MCCR4_ACTTORW_SHIFT) |
+ (((CFG_BSTOPRE & 0x03c0) >> 6) <<MCCR4_BSTOPRE6TO9_SHIFT ));
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+
+ CONFIG_WRITE_WORD(MSAR1,
+ ( (CFG_BANK0_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+ (((CFG_BANK1_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+ (((CFG_BANK2_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+ (((CFG_BANK3_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(EMSAR1,
+ ( (CFG_BANK0_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+ (((CFG_BANK1_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+ (((CFG_BANK2_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+ (((CFG_BANK3_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(MSAR2,
+ ( (CFG_BANK4_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+ (((CFG_BANK5_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+ (((CFG_BANK6_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+ (((CFG_BANK7_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(EMSAR2,
+ ( (CFG_BANK4_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+ (((CFG_BANK5_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+ (((CFG_BANK6_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+ (((CFG_BANK7_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(MEAR1,
+ ( (CFG_BANK0_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+ (((CFG_BANK1_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+ (((CFG_BANK2_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+ (((CFG_BANK3_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(EMEAR1,
+ ( (CFG_BANK0_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+ (((CFG_BANK1_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+ (((CFG_BANK2_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+ (((CFG_BANK3_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(MEAR2,
+ ( (CFG_BANK4_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+ (((CFG_BANK5_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+ (((CFG_BANK6_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+ (((CFG_BANK7_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(EMEAR2,
+ ( (CFG_BANK4_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+ (((CFG_BANK5_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+ (((CFG_BANK6_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+ (((CFG_BANK7_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+
+ CONFIG_WRITE_BYTE(ODCR, CFG_ODCR);
+#ifdef CFG_DLL_MAX_DELAY
+ CONFIG_WRITE_BYTE(MIOCR1, CFG_DLL_MAX_DELAY); /* needed to make DLL lock */
+#endif
+#if defined(CFG_DLL_EXTEND) && defined(CFG_PCI_HOLD_DEL)
+ CONFIG_WRITE_BYTE(PMCR2, CFG_DLL_EXTEND | CFG_PCI_HOLD_DEL);
+#endif
+#if defined(MIOCR2) && defined(CFG_SDRAM_DSCD)
+ CONFIG_WRITE_BYTE(MIOCR2, CFG_SDRAM_DSCD); /* change memory input */
+#endif /* setup & hold time */
+
+ CONFIG_WRITE_BYTE(MBER,
+ CFG_BANK0_ENABLE |
+ (CFG_BANK1_ENABLE << 1) |
+ (CFG_BANK2_ENABLE << 2) |
+ (CFG_BANK3_ENABLE << 3) |
+ (CFG_BANK4_ENABLE << 4) |
+ (CFG_BANK5_ENABLE << 5) |
+ (CFG_BANK6_ENABLE << 6) |
+ (CFG_BANK7_ENABLE << 7));
+
+#ifdef CFG_PGMAX
+ CONFIG_WRITE_BYTE(MPMR, CFG_PGMAX);
+#endif
+
+ /* ! Wait 200us before initialize other registers */
+ /*FIXME: write a decent udelay wait */
+ __asm__ __volatile__(
+ " mtctr %0 \n \
+ 0: bdnz 0b\n"
+ :
+ : "r" (0x10000));
+
+ CONFIG_READ_WORD(MCCR1, val);
+ CONFIG_WRITE_WORD(MCCR1, val | MCCR1_MEMGO); /* set memory access going */
+ __asm__ __volatile__("eieio");
+
+#endif /* !CONFIG_MOUSSE && !CONFIG_BMW */
+}
+
+
+#ifdef CONFIG_MOUSSE
+#ifdef INCLUDE_MPC107_REPORT
+struct MPC107_s{
+ unsigned int iobase;
+ char desc[120];
+} MPC107Regs[] ={
+ {BMC_BASE+0x0, "MPC107 Vendor/Device ID"},
+ {BMC_BASE+0x4, "MPC107 PCI Command/Status Register"},
+ {BMC_BASE+0x8, "MPC107 Revision"},
+ {BMC_BASE+0xC, "MPC107 Cache Line Size"},
+ {BMC_BASE+0x10, "MPC107 LMBAR"},
+ {BMC_BASE+0x14, "MPC824x PCSR"},
+ {BMC_BASE+0xA8, "MPC824x PICR1"},
+ {BMC_BASE+0xAC, "MPC824x PICR2"},
+ {BMC_BASE+0x46, "MPC824x PACR"},
+ {BMC_BASE+0x310, "MPC824x ITWR"},
+ {BMC_BASE+0x300, "MPC824x OMBAR"},
+ {BMC_BASE+0x308, "MPC824x OTWR"},
+ {BMC_BASE+0x14, "MPC107 Peripheral Control and Status Register"},
+ {BMC_BASE+0x78, "MPC107 EUMBAR"},
+ {BMC_BASE+0xC0, "MPC107 Processor Bus Error Status"},
+ {BMC_BASE+0xC4, "MPC107 PCI Bus Error Status"},
+ {BMC_BASE+0xC8, "MPC107 Processor/PCI Error Address"},
+ {BMC_BASE+0xE0, "MPC107 AMBOR Register"},
+ {BMC_BASE+0xF0, "MPC107 MCCR1 Register"},
+ {BMC_BASE+0xF4, "MPC107 MCCR2 Register"},
+ {BMC_BASE+0xF8, "MPC107 MCCR3 Register"},
+ {BMC_BASE+0xFC, "MPC107 MCCR4 Register"}
+};
+#define N_MPC107_Regs (sizeof(MPC107Regs)/sizeof(MPC107Regs[0]))
+#endif /* INCLUDE_MPC107_REPORT */
+#endif /* CONFIG_MOUSSE */
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+#ifdef CONFIG_MOUSSE
+#ifdef INCLUDE_MPC107_REPORT
+ unsigned int tmp = 0, i;
+#endif
+ /*
+ * Initialize the EUMBBAR (Embedded Util Mem Block Base Addr Reg).
+ * This is necessary before the EPIC, DMA ctlr, I2C ctlr, etc. can
+ * be accessed.
+ */
+
+#ifdef CONFIG_MPC8240 /* only on MPC8240 */
+ mpc824x_mpc107_setreg (EUMBBAR, EUMBBAR_VAL);
+ /* MOT/SPS: Issue #10002, PCI (FD Alias enable) */
+ mpc824x_mpc107_setreg (AMBOR, 0x000000C0);
+#endif
+
+
+#ifdef INCLUDE_MPC107_REPORT
+ /* Check MPC824x PCI Device and Vendor ID */
+ while ((tmp = mpc824x_mpc107_getreg (BMC_BASE)) != 0x31057) {
+ printf (" MPC107: offset=0x%x, val = 0x%x\n",
+ BMC_BASE,
+ tmp);
+ }
+
+ for (i = 0; i < N_MPC107_Regs; i++) {
+ printf (" 0x%x/%s = 0x%x\n",
+ MPC107Regs[i].iobase,
+ MPC107Regs[i].desc,
+ mpc824x_mpc107_getreg (MPC107Regs[i].iobase));
+ }
+
+ printf ("IBAT0L = 0x%08X\n", mfspr (IBAT0L));
+ printf ("IBAT0U = 0x%08X\n", mfspr (IBAT0U));
+ printf ("IBAT1L = 0x%08X\n", mfspr (IBAT1L));
+ printf ("IBAT1U = 0x%08X\n", mfspr (IBAT1U));
+ printf ("IBAT2L = 0x%08X\n", mfspr (IBAT2L));
+ printf ("IBAT2U = 0x%08X\n", mfspr (IBAT2U));
+ printf ("IBAT3L = 0x%08X\n", mfspr (IBAT3L));
+ printf ("IBAT3U = 0x%08X\n", mfspr (IBAT3U));
+ printf ("DBAT0L = 0x%08X\n", mfspr (DBAT0L));
+ printf ("DBAT0U = 0x%08X\n", mfspr (DBAT0U));
+ printf ("DBAT1L = 0x%08X\n", mfspr (DBAT1L));
+ printf ("DBAT1U = 0x%08X\n", mfspr (DBAT1U));
+ printf ("DBAT2L = 0x%08X\n", mfspr (DBAT2L));
+ printf ("DBAT2U = 0x%08X\n", mfspr (DBAT2U));
+ printf ("DBAT3L = 0x%08X\n", mfspr (DBAT3L));
+ printf ("DBAT3U = 0x%08X\n", mfspr (DBAT3U));
+#endif /* INCLUDE_MPC107_REPORT */
+#endif /* CONFIG_MOUSSE */
+ return (0);
+}
diff --git a/cpu/mpc824x/drivers/i2c/i2c1.c b/cpu/mpc824x/drivers/i2c/i2c1.c
new file mode 100644
index 0000000..be6ec60
--- /dev/null
+++ b/cpu/mpc824x/drivers/i2c/i2c1.c
@@ -0,0 +1,1228 @@
+/*************************************************************
+ *
+ * Copyright @ Motorola, 1999
+ *
+ ************************************************************/
+#include <common.h>
+
+#ifdef CONFIG_HARD_I2C
+#include <i2c.h>
+#include "i2c_export.h"
+#include "i2c.h"
+
+#undef I2CDBG0
+#undef DEBUG
+
+/* Define a macro to use an optional application-layer print function, if
+ * one was passed to the I2C library during initialization. If there was
+ * no function pointer passed, this protects against calling it. Also define
+ * the global variable that holds the passed pointer.
+ */
+#define TIMEOUT (CFG_HZ/4)
+#define PRINT if ( app_print ) app_print
+static int (*app_print) (char *, ...);
+
+/******************* Internal to I2C Driver *****************/
+static unsigned int ByteToXmit = 0;
+static unsigned int XmitByte = 0;
+static unsigned char *XmitBuf = 0;
+static unsigned int XmitBufEmptyStop = 0;
+static unsigned int ByteToRcv = 0;
+static unsigned int RcvByte = 0;
+static unsigned char *RcvBuf = 0;
+static unsigned int RcvBufFulStop = 0;
+static unsigned int MasterRcvAddress = 0;
+
+/* Set by call to get_eumbbar during I2C_Initialize.
+ * This could be globally available to the I2C library, but there is
+ * an advantage to passing it as a parameter: it is already in a register
+ * and doesn't have to be loaded from memory. Also, that is the way the
+ * I2C library was already implemented and I don't want to change it without
+ * a more detailed analysis.
+ * It is being set as a global variable in I2C_Initialize to hide it from
+ * the DINK application layer, because it is Kahlua-specific. I think that
+ * get_eumbbar, load_runtime_reg, and store_runtime_reg should be defined in
+ * a Kahlua-specific library dealing with the embedded utilities memory block.
+ * Right now, get_eumbbar is defined in dink32/kahlua.s. The other two are
+ * defined in dink32/drivers/i2c/i2c2.s.
+ */
+static unsigned int Global_eumbbar = 0;
+
+extern unsigned int load_runtime_reg (unsigned int eumbbar,
+ unsigned int reg);
+
+extern unsigned int store_runtime_reg (unsigned int eumbbar,
+ unsigned int reg, unsigned int val);
+
+/************************** API *****************/
+
+/* Application Program Interface (API) are the calls provided by the I2C
+ * library to upper layer applications (i.e., DINK) to access the Kahlua
+ * I2C bus interface. The functions and values that are part of this API
+ * are declared in i2c_export.h.
+ */
+
+/* Initialize I2C unit with the following:
+ * driver's slave address
+ * interrupt enabled
+ * optional pointer to application layer print function
+ *
+ * These parameters may be added:
+ * desired clock rate
+ * digital filter frequency sampling rate
+ *
+ * This function must be called before I2C unit can be used.
+ */
+I2C_Status I2C_Initialize (unsigned char addr,
+ I2C_INTERRUPT_MODE en_int,
+ int (*p) (char *, ...))
+{
+ I2CStatus status;
+
+ /* establish the pointer, if there is one, to the application's "printf" */
+ app_print = p;
+
+ /* If this is the first call, get the embedded utilities memory block
+ * base address. I'm not sure what to do about error handling here:
+ * if a non-zero value is returned, accept it.
+ */
+ if (Global_eumbbar == 0)
+ Global_eumbbar = get_eumbbar ();
+ if (Global_eumbbar == 0) {
+ PRINT ("I2C_Initialize: can't find EUMBBAR\n");
+ return I2C_ERROR;
+ }
+
+ /* validate the I2C address */
+ if (addr & 0x80) {
+ PRINT ("I2C_Initialize, I2C address invalid: %d 0x%x\n",
+ (unsigned int) addr, (unsigned int) addr);
+ return I2C_ERROR;
+ }
+
+ /* Call the internal I2C library function to perform work.
+ * Accept the default frequency sampling rate (no way to set it currently,
+ * via I2C_Init) and set the clock frequency to something reasonable.
+ */
+ status = I2C_Init (Global_eumbbar, (unsigned char) 0x31, addr, en_int);
+ if (status != I2CSUCCESS) {
+ PRINT ("I2C_Initialize: error in initiation\n");
+ return I2C_ERROR;
+ }
+
+ /* all is well */
+ return I2C_SUCCESS;
+}
+
+
+/* Perform the given I2C transaction, only MASTER_XMIT and MASTER_RCV
+ * are implemented. Both are only in polling mode.
+ *
+ * en_int controls interrupt/polling mode
+ * act is the type of transaction
+ * i2c_addr is the I2C address of the slave device
+ * data_addr is the address of the data on the slave device
+ * len is the length of data to send or receive
+ * buffer is the address of the data buffer
+ * stop = I2C_NO_STOP, don't signal STOP at end of transaction
+ * I2C_STOP, signal STOP at end of transaction
+ * retry is the timeout retry value, currently ignored
+ * rsta = I2C_NO_RESTART, this is not continuation of existing transaction
+ * I2C_RESTART, this is a continuation of existing transaction
+ */
+I2C_Status I2C_do_transaction ( I2C_INTERRUPT_MODE en_int,
+ I2C_TRANSACTION_MODE act,
+ unsigned char i2c_addr,
+ unsigned char data_addr,
+ int len,
+ char *buffer,
+ I2C_STOP_MODE stop,
+ int retry, I2C_RESTART_MODE rsta)
+{
+ I2C_Status status;
+ unsigned char data_addr_buffer[1];
+
+#if 1
+/* This is a temporary work-around. The I2C library breaks the protocol
+ * if it attempts to handle a data transmission in more than one
+ * transaction, so the data address and the actual data bytes are put
+ * into a single buffer before sending it to the library internal functions.
+ * The problem is related to being able to restart a transaction without
+ * sending the I2C device address or repeating the data address. It may take
+ * a day or two to sort it all out, so I'll have to get back to it later.
+ * Look at I2C_Start to see about using some status flags (I'm not sure that
+ * "stop" and "rsta" are enough to reflect the states, maybe so; but the logic
+ * in the library is insufficient) to control correct handling of the protocol.
+ */
+ unsigned char dummy_buffer[257];
+
+ if (act == I2C_MASTER_XMIT) {
+ int i;
+
+ if (len > 256)
+ return I2C_ERROR;
+ for (i = 1; i <= len; i++)
+ dummy_buffer[i] = buffer[i - 1];
+ dummy_buffer[0] = data_addr;
+ status = I2C_do_buffer (en_int, act, i2c_addr, 1 + len,
+ dummy_buffer, stop, retry, rsta);
+ if (status != I2C_SUCCESS) {
+ PRINT ("I2C_do_transaction: can't perform data transfer\n");
+ return I2C_ERROR;
+ }
+ return I2C_SUCCESS;
+ }
+#endif /* end of temp work-around */
+
+ /* validate requested transaction type */
+ if ((act != I2C_MASTER_XMIT) && (act != I2C_MASTER_RCV)) {
+ PRINT ("I2C_do_transaction, invalid transaction request: %d\n",
+ act);
+ return I2C_ERROR;
+ }
+
+ /* range check the I2C address */
+ if (i2c_addr & 0x80) {
+ PRINT ("I2C_do_transaction, I2C address out of range: %d 0x%x\n",
+ (unsigned int) i2c_addr, (unsigned int) i2c_addr);
+ return I2C_ERROR;
+ } else {
+ data_addr_buffer[0] = data_addr;
+ }
+
+ /*
+ * We first have to contact the slave device and transmit the
+ * data address. Be careful about the STOP and restart stuff.
+ * We don't want to signal STOP after sending the data
+ * address, but this could be a continuation if the
+ * application didn't release the bus after the previous
+ * transaction, by not sending a STOP after it.
+ */
+ status = I2C_do_buffer (en_int, I2C_MASTER_XMIT, i2c_addr, 1,
+ data_addr_buffer, I2C_NO_STOP, retry, rsta);
+ if (status != I2C_SUCCESS) {
+ PRINT ("I2C_do_transaction: can't send data address for read\n");
+ return I2C_ERROR;
+ }
+
+ /* The data transfer will be a continuation. */
+ rsta = I2C_RESTART;
+
+ /* now handle the user data */
+ status = I2C_do_buffer (en_int, act, i2c_addr, len,
+ buffer, stop, retry, rsta);
+ if (status != I2C_SUCCESS) {
+ PRINT ("I2C_do_transaction: can't perform data transfer\n");
+ return I2C_ERROR;
+ }
+
+ /* all is well */
+ return I2C_SUCCESS;
+}
+
+/* This function performs the work for I2C_do_transaction. The work is
+ * split into this function to enable I2C_do_transaction to first transmit
+ * the data address to the I2C slave device without putting the data address
+ * into the first byte of the buffer.
+ *
+ * en_int controls interrupt/polling mode
+ * act is the type of transaction
+ * i2c_addr is the I2C address of the slave device
+ * len is the length of data to send or receive
+ * buffer is the address of the data buffer
+ * stop = I2C_NO_STOP, don't signal STOP at end of transaction
+ * I2C_STOP, signal STOP at end of transaction
+ * retry is the timeout retry value, currently ignored
+ * rsta = I2C_NO_RESTART, this is not continuation of existing transaction
+ * I2C_RESTART, this is a continuation of existing transaction
+ */
+static I2C_Status I2C_do_buffer (I2C_INTERRUPT_MODE en_int,
+ I2C_TRANSACTION_MODE act,
+ unsigned char i2c_addr,
+ int len,
+ unsigned char *buffer,
+ I2C_STOP_MODE stop,
+ int retry, I2C_RESTART_MODE rsta)
+{
+ I2CStatus rval;
+ unsigned int dev_stat;
+
+ if (act == I2C_MASTER_RCV) {
+ /* set up for master-receive transaction */
+ rval = I2C_get (Global_eumbbar, i2c_addr, buffer, len, stop, rsta);
+ } else {
+ /* set up for master-transmit transaction */
+ rval = I2C_put (Global_eumbbar, i2c_addr, buffer, len, stop, rsta);
+ }
+
+ /* validate the setup */
+ if (rval != I2CSUCCESS) {
+ dev_stat = load_runtime_reg (Global_eumbbar, I2CSR);
+ PRINT ("Error(I2C_do_buffer): control phase, code(0x%08x), status(0x%08x)\n", rval, dev_stat);
+ I2C_Stop (Global_eumbbar);
+ return I2C_ERROR;
+ }
+
+ if (en_int == 1) {
+ /* this should not happen, no interrupt handling yet */
+ return I2C_SUCCESS;
+ }
+
+ /* this performs the polling action, when the transfer is completed,
+ * the status returned from I2C_Timer_Event will be I2CBUFFFULL or
+ * I2CBUFFEMPTY (rcv or xmit), I2CSUCCESS or I2CADDRESS indicates the
+ * transaction is not yet complete, anything else is an error.
+ */
+ while (rval == I2CSUCCESS || rval == I2CADDRESS) {
+ int timeval = get_timer (0);
+
+ /* poll the device until something happens */
+ do {
+ rval = I2C_Timer_Event (Global_eumbbar, 0);
+ }
+ while (rval == I2CNOEVENT && get_timer (timeval) < TIMEOUT);
+
+ /* check for error condition */
+ if (rval == I2CSUCCESS ||
+ rval == I2CBUFFFULL ||
+ rval == I2CBUFFEMPTY ||
+ rval == I2CADDRESS) {
+ ; /* do nothing */
+ } else {
+ /* report the error condition */
+ dev_stat = load_runtime_reg (Global_eumbbar, I2CSR);
+ PRINT ("Error(I2C_do_buffer): code(0x%08x), status(0x%08x)\n",
+ rval, dev_stat);
+ return I2C_ERROR;
+ }
+ }
+
+ /* all is well */
+ return I2C_SUCCESS;
+}
+
+/**
+ * Note:
+ *
+ * In all following functions,
+ * the caller shall pass the configured embedded utility memory
+ * block base, EUMBBAR.
+ **/
+
+/***********************************************************
+ * function: I2C_put
+ *
+ * description:
+ Send a buffer of data to the intended rcv_addr.
+ * If stop_flag is set, after the whole buffer
+ * is sent, generate a STOP signal provided that the
+ * receiver doesn't signal the STOP in the middle.
+ * I2C is the master performing transmitting. If
+ * no STOP signal is generated at the end of current
+ * transaction, the master can generate a START signal
+ * to another slave addr.
+ *
+ * note: this is master xmit API
+ *********************************************************/
+static I2CStatus I2C_put (unsigned int eumbbar, unsigned char rcv_addr, /* receiver's address */
+ unsigned char *buffer_ptr, /* pointer of data to be sent */
+ unsigned int length, /* number of byte of in the buffer */
+ unsigned int stop_flag, /* 1 - signal STOP when buffer is empty
+ * 0 - no STOP signal when buffer is empty
+ */
+ unsigned int is_cnt)
+{ /* 1 - this is a restart, don't check MBB
+ * 0 - this is a new start, check MBB
+ */
+ if (buffer_ptr == 0 || length == 0) {
+ return I2CERROR;
+ }
+#ifdef I2CDBG0
+ PRINT ("%s(%d): I2C_put\n", __FILE__, __LINE__);
+#endif
+
+ XmitByte = 0;
+ ByteToXmit = length;
+ XmitBuf = buffer_ptr;
+ XmitBufEmptyStop = stop_flag;
+
+ RcvByte = 0;
+ ByteToRcv = 0;
+ RcvBuf = 0;
+
+ /* we are the master, start transaction */
+ return I2C_Start (eumbbar, rcv_addr, XMIT, is_cnt);
+}
+
+/***********************************************************
+ * function: I2C_get
+ *
+ * description:
+ * Receive a buffer of data from the desired sender_addr
+ * If stop_flag is set, when the buffer is full and the
+ * sender does not signal STOP, generate a STOP signal.
+ * I2C is the master performing receiving. If no STOP signal
+ * is generated, the master can generate a START signal
+ * to another slave addr.
+ *
+ * note: this is master receive API
+ **********************************************************/
+static I2CStatus I2C_get (unsigned int eumbbar, unsigned char rcv_from, /* sender's address */
+ unsigned char *buffer_ptr, /* pointer of receiving buffer */
+ unsigned int length, /* length of the receiving buffer */
+ unsigned int stop_flag, /* 1 - signal STOP when buffer is full
+ * 0 - no STOP signal when buffer is full
+ */
+ unsigned int is_cnt)
+{ /* 1 - this is a restart, don't check MBB
+ * 0 - this is a new start, check MBB
+ */
+ if (buffer_ptr == 0 || length == 0) {
+ return I2CERROR;
+ }
+#ifdef I2CDBG0
+ PRINT ("%s(%d): I2C_get\n", __FILE__, __LINE__);
+#endif
+
+ RcvByte = 0;
+ ByteToRcv = length;
+ RcvBuf = buffer_ptr;
+ RcvBufFulStop = stop_flag;
+
+ XmitByte = 0;
+ ByteToXmit = 0;
+ XmitBuf = 0;
+
+ /* we are the master, start the transaction */
+ return I2C_Start (eumbbar, rcv_from, RCV, is_cnt);
+
+}
+
+#if 0 /* turn off dead code */
+/*********************************************************
+ * function: I2C_write
+ *
+ * description:
+ * Send a buffer of data to the requiring master.
+ * If stop_flag is set, after the whole buffer is sent,
+ * generate a STOP signal provided that the requiring
+ * receiver doesn't signal the STOP in the middle.
+ * I2C is the slave performing transmitting.
+ *
+ * Note: this is slave xmit API.
+ *
+ * due to the current Kahlua design, slave transmitter
+ * shall not signal STOP since there is no way
+ * for master to detect it, causing I2C bus hung.
+ *
+ * For the above reason, the stop_flag is always
+ * set, i.e., 0.
+ *
+ * programmer shall use the timer on Kahlua to
+ * control the interval of data byte at the
+ * master side.
+ *******************************************************/
+static I2CStatus I2C_write (unsigned int eumbbar, unsigned char *buffer_ptr, /* pointer of data to be sent */
+ unsigned int length, /* number of byte of in the buffer */
+ unsigned int stop_flag)
+{ /* 1 - signal STOP when buffer is empty
+ * 0 - no STOP signal when buffer is empty
+ */
+ if (buffer_ptr == 0 || length == 0) {
+ return I2CERROR;
+ }
+
+ XmitByte = 0;
+ ByteToXmit = length;
+ XmitBuf = buffer_ptr;
+ XmitBufEmptyStop = 0; /* in order to avoid bus hung, ignored the user's stop_flag */
+
+ RcvByte = 0;
+ ByteToRcv = 0;
+ RcvBuf = 0;
+
+ /* we are the slave, just wait for being called, or pull */
+ /* I2C_Timer_Event( eumbbar ); */
+}
+
+/******************************************************
+ * function: I2C_read
+ *
+ * description:
+ * Receive a buffer of data from the sending master.
+ * If stop_flag is set, when the buffer is full and the
+ * sender does not signal STOP, generate a STOP signal.
+ * I2C is the slave performing receiving.
+ *
+ * note: this is slave receive API
+ ****************************************************/
+static I2CStatus I2C_read (unsigned int eumbbar, unsigned char *buffer_ptr, /* pointer of receiving buffer */
+ unsigned int length, /* length of the receiving buffer */
+ unsigned int stop_flag)
+{ /* 1 - signal STOP when buffer is full
+ * 0 - no STOP signal when buffer is full
+ */
+ if (buffer_ptr == 0 || length == 0) {
+ return I2CERROR;
+ }
+
+ RcvByte = 0;
+ ByteToRcv = length;
+ RcvBuf = buffer_ptr;
+ RcvBufFulStop = stop_flag;
+
+ XmitByte = 0;
+ ByteToXmit = 0;
+ XmitBuf = 0;
+
+ /* wait for master to call us, or poll */
+ /* I2C_Timer_Event( eumbbar ); */
+}
+#endif /* turn off dead code */
+
+/*********************************************************
+ * function: I2c_Timer_Event
+ *
+ * description:
+ * if interrupt is not used, this is the timer event handler.
+ * After each fixed time interval, this function can be called
+ * to check the I2C status and call appropriate function to
+ * handle the status event.
+ ********************************************************/
+static I2CStatus I2C_Timer_Event (unsigned int eumbbar,
+ I2CStatus (*handler) (unsigned int))
+{
+ I2C_STAT stat;
+
+#ifdef I2CDBG0
+ PRINT ("%s(%d): I2C_Timer_Event\n", __FILE__, __LINE__);
+#endif
+
+ stat = I2C_Get_Stat (eumbbar);
+
+ if (stat.mif == 1) {
+ if (handler == 0) {
+ return I2C_ISR (eumbbar);
+ } else {
+ return (*handler) (eumbbar);
+ }
+ }
+
+ return I2CNOEVENT;
+}
+
+
+/****************** Device I/O function *****************/
+
+/******************************************************
+ * function: I2C_Start
+ *
+ * description: Generate a START signal in the desired mode.
+ * I2C is the master.
+ *
+ * Return I2CSUCCESS if no error.
+ *
+ * note:
+ ****************************************************/
+static I2CStatus I2C_Start (unsigned int eumbbar, unsigned char slave_addr, /* address of the receiver */
+ I2C_MODE mode, /* XMIT(1) - put (write)
+ * RCV(0) - get (read)
+ */
+ unsigned int is_cnt)
+{ /* 1 - this is a restart, don't check MBB
+ * 0 - this is a new start
+ */
+ unsigned int tmp = 0;
+ I2C_STAT stat;
+ I2C_CTRL ctrl;
+
+#ifdef I2CDBG0
+ PRINT ("%s(%d): I2C_Start addr 0x%x mode %d cnt %d\n", __FILE__,
+ __LINE__, slave_addr, mode, is_cnt);
+#endif
+
+ ctrl = I2C_Get_Ctrl (eumbbar);
+
+ /* first make sure I2C has been initialized */
+ if (ctrl.men == 0) {
+ return I2CERROR;
+ }
+
+ /* next make sure bus is idle */
+ stat = I2C_Get_Stat (eumbbar);
+
+ if (is_cnt == 0 && stat.mbb == 1) {
+ /* sorry, we lost */
+ return I2CBUSBUSY;
+ } else if (is_cnt == 1 && stat.mif == 1 && stat.mal == 0) {
+ /* sorry, we lost the bus */
+ return I2CALOSS;
+ }
+
+
+ /* OK, I2C is enabled and we have the bus */
+
+ /* prepare to write the slave address */
+ ctrl.msta = 1;
+ ctrl.mtx = 1;
+ ctrl.txak = 0;
+ ctrl.rsta = is_cnt; /* set the repeat start bit */
+ I2C_Set_Ctrl (eumbbar, ctrl);
+
+ /* write the slave address and xmit/rcv mode bit */
+ tmp = load_runtime_reg (eumbbar, I2CDR);
+ tmp = (tmp & 0xffffff00) |
+ ((slave_addr & 0x007f) << 1) |
+ (mode == XMIT ? 0x0 : 0x1);
+ store_runtime_reg (eumbbar, I2CDR, tmp);
+
+ if (mode == RCV) {
+ MasterRcvAddress = 1;
+ } else {
+ MasterRcvAddress = 0;
+ }
+
+#ifdef I2CDBG0
+ PRINT ("%s(%d): I2C_Start exit\n", __FILE__, __LINE__);
+#endif
+
+ /* wait for the interrupt or poll */
+ return I2CSUCCESS;
+}
+
+/***********************************************************
+ * function: I2c_Stop
+ *
+ * description: Generate a STOP signal to terminate the master
+ * transaction.
+ * return I2CSUCCESS
+ *
+ **********************************************************/
+static I2CStatus I2C_Stop (unsigned int eumbbar)
+{
+ I2C_CTRL ctrl;
+
+#ifdef I2CDBG0
+ PRINT ("%s(%d): I2C_Stop enter\n", __FILE__, __LINE__);
+#endif
+
+ ctrl = I2C_Get_Ctrl (eumbbar);
+ ctrl.msta = 0;
+ I2C_Set_Ctrl (eumbbar, ctrl);
+
+#ifdef I2CDBG0
+ PRINT ("%s(%d): I2C_Stop exit\n", __FILE__, __LINE__);
+#endif
+
+ return I2CSUCCESS;
+}
+
+/****************************************************
+ * function: I2C_Master_Xmit
+ *
+ * description: Master sends one byte of data to
+ * slave target
+ *
+ * return I2CSUCCESS if the byte transmitted.
+ * Otherwise no-zero
+ *
+ * Note: condition must meet when this function is called:
+ * I2CSR(MIF) == 1 && I2CSR(MCF) == 1 && I2CSR(RXAK) == 0
+ * I2CCR(MSTA) == 1 && I2CCR(MTX) == 1
+ *
+ ***************************************************/
+static I2CStatus I2C_Master_Xmit (unsigned int eumbbar)
+{
+ unsigned int val;
+
+ if (ByteToXmit > 0) {
+
+ if (ByteToXmit == XmitByte) {
+ /* all xmitted */
+ ByteToXmit = 0;
+
+ if (XmitBufEmptyStop == 1) {
+ I2C_Stop (eumbbar);
+ }
+
+ return I2CBUFFEMPTY;
+
+ }
+#ifdef I2CDBG0
+ PRINT ("%s(%d): xmit 0x%02x\n", __FILE__, __LINE__,
+ *(XmitBuf + XmitByte));
+#endif
+
+ val = *(XmitBuf + XmitByte);
+ val &= 0x000000ff;
+ store_runtime_reg (eumbbar, I2CDR, val);
+ XmitByte++;
+
+ return I2CSUCCESS;
+
+ }
+
+ return I2CBUFFEMPTY;
+}
+
+/***********************************************
+ * function: I2C_Master_Rcv
+ *
+ * description: master reads one byte data
+ * from slave source
+ *
+ * return I2CSUCCESS if no error
+ *
+ * Note: condition must meet when this function is called:
+ * I2CSR(MIF) == 1 && I2CSR(MCF) == 1 &&
+ * I2CCR(MSTA) == 1 && I2CCR(MTX) == 0
+ *
+ ***********************************************/
+static I2CStatus I2C_Master_Rcv (unsigned int eumbbar)
+{
+ I2C_CTRL ctrl;
+ unsigned int val;
+
+ if (ByteToRcv > 0) {
+
+ if (ByteToRcv - RcvByte == 2 && RcvBufFulStop == 1) {
+ /* master requests more than or equal to 2 bytes
+ * we are reading 2nd to last byte
+ */
+
+ /* we need to set I2CCR(TXAK) to generate a STOP */
+ ctrl = I2C_Get_Ctrl (eumbbar);
+ ctrl.txak = 1;
+ I2C_Set_Ctrl (eumbbar, ctrl);
+
+ /* Kahlua will automatically generate a STOP
+ * next time a transaction happens
+ */
+
+ /* note: the case of master requesting one byte is
+ * handled in I2C_ISR
+ */
+ }
+
+ /* generat a STOP before reading the last byte */
+ if (RcvByte + 1 == ByteToRcv && RcvBufFulStop == 1) {
+ I2C_Stop (eumbbar);
+ }
+
+ val = load_runtime_reg (eumbbar, I2CDR);
+ *(RcvBuf + RcvByte) = val & 0xFF;
+
+#ifdef I2CDBG0
+ PRINT ("%s(%d): rcv 0x%02x\n", __FILE__, __LINE__,
+ *(RcvBuf + RcvByte));
+#endif
+
+ RcvByte++;
+
+ if (ByteToRcv == RcvByte) {
+ ByteToRcv = 0;
+
+ return I2CBUFFFULL;
+ }
+
+ return I2CSUCCESS;
+ }
+
+ return I2CBUFFFULL;
+
+}
+
+/****************************************************
+ * function: I2C_Slave_Xmit
+ *
+ * description: Slave sends one byte of data to
+ * requesting destination
+ *
+ * return SUCCESS if the byte transmitted. Otherwise
+ * No-zero
+ *
+ * Note: condition must meet when this function is called:
+ * I2CSR(MIF) == 1 && I2CSR(MCF) == 1 && I2CSR(RXAK) = 0
+ * I2CCR(MSTA) == 0 && I2CCR(MTX) == 1
+ *
+ ***************************************************/
+static I2CStatus I2C_Slave_Xmit (unsigned int eumbbar)
+{
+ unsigned int val;
+
+ if (ByteToXmit > 0) {
+
+ if (ByteToXmit == XmitByte) {
+ /* no more data to send */
+ ByteToXmit = 0;
+
+ /*
+ * do not toggle I2CCR(MTX). Doing so will
+ * cause bus-hung since current Kahlua design
+ * does not give master a way to detect slave
+ * stop. It is always a good idea for master
+ * to use timer to prevent the long long
+ * delays
+ */
+
+ return I2CBUFFEMPTY;
+ }
+#ifdef I2CDBG
+ PRINT ("%s(%d): xmit 0x%02x\n", __FILE__, __LINE__,
+ *(XmitBuf + XmitByte));
+#endif
+
+ val = *(XmitBuf + XmitByte);
+ val &= 0x000000ff;
+ store_runtime_reg (eumbbar, I2CDR, val);
+ XmitByte++;
+
+ return I2CSUCCESS;
+ }
+
+ return I2CBUFFEMPTY;
+}
+
+/***********************************************
+ * function: I2C_Slave_Rcv
+ *
+ * description: slave reads one byte data
+ * from master source
+ *
+ * return I2CSUCCESS if no error otherwise non-zero
+ *
+ * Note: condition must meet when this function is called:
+ * I2CSR(MIF) == 1 && I2CSR(MCF) == 1 &&
+ * I2CCR(MSTA) == 0 && I2CCR(MTX) = 0
+ *
+ ***********************************************/
+static I2CStatus I2C_Slave_Rcv (unsigned int eumbbar)
+{
+ unsigned int val;
+ I2C_CTRL ctrl;
+
+ if (ByteToRcv > 0) {
+ val = load_runtime_reg (eumbbar, I2CDR);
+ *(RcvBuf + RcvByte) = val & 0xff;
+#ifdef I2CDBG
+ PRINT ("%s(%d): rcv 0x%02x\n", __FILE__, __LINE__,
+ *(RcvBuf + RcvByte));
+#endif
+ RcvByte++;
+
+ if (ByteToRcv == RcvByte) {
+ if (RcvBufFulStop == 1) {
+ /* all done */
+ ctrl = I2C_Get_Ctrl (eumbbar);
+ ctrl.txak = 1;
+ I2C_Set_Ctrl (eumbbar, ctrl);
+ }
+
+ ByteToRcv = 0;
+ return I2CBUFFFULL;
+ }
+
+ return I2CSUCCESS;
+ }
+
+ return I2CBUFFFULL;
+}
+
+/****************** Device Control Function *************/
+
+/*********************************************************
+ * function: I2C_Init
+ *
+ * description: Initialize I2C unit with desired frequency divider,
+ * master's listening address, with interrupt enabled
+ * or disabled.
+ *
+ * note:
+ ********************************************************/
+static I2CStatus I2C_Init (unsigned int eumbbar, unsigned char fdr, /* frequency divider */
+ unsigned char slave_addr, /* driver's address used for receiving */
+ unsigned int en_int)
+{ /* 1 - enable I2C interrupt
+ * 0 - disable I2C interrup
+ */
+ I2C_CTRL ctrl;
+ unsigned int tmp;
+
+#ifdef I2CDBG0
+ PRINT ("%s(%d): I2C_Init enter\n", __FILE__, __LINE__);
+#endif
+
+ ctrl = I2C_Get_Ctrl (eumbbar);
+ /* disable the I2C module before we change everything */
+ ctrl.men = 0;
+ I2C_Set_Ctrl (eumbbar, ctrl);
+
+ /* set the frequency diver */
+ tmp = load_runtime_reg (eumbbar, I2CFDR);
+ tmp = (tmp & 0xffffffc0) | (fdr & 0x3f);
+ store_runtime_reg (eumbbar, I2CFDR, tmp);
+
+ /* Set our listening (slave) address */
+ tmp = load_runtime_reg (eumbbar, I2CADR);
+ tmp = (tmp & 0xffffff01) | ((slave_addr & 0x7f) << 1);
+ store_runtime_reg (eumbbar, I2CADR, tmp);
+
+ /* enable I2C with desired interrupt setting */
+ ctrl.men = 1;
+ ctrl.mien = en_int & 0x1;
+ I2C_Set_Ctrl (eumbbar, ctrl);
+#ifdef I2CDBG0
+ PRINT ("%s(%d): I2C_Init exit\n", __FILE__, __LINE__);
+#endif
+
+ return I2CSUCCESS;
+
+}
+
+/*****************************************
+ * function I2c_Get_Stat
+ *
+ * description: Query I2C Status, i.e., read I2CSR
+ *
+ ****************************************/
+static I2C_STAT I2C_Get_Stat (unsigned int eumbbar)
+{
+ unsigned int temp;
+ I2C_STAT stat;
+
+ temp = load_runtime_reg (eumbbar, I2CSR);
+
+#ifdef I2CDBG0
+ PRINT ("%s(%d): get stat = 0x%08x\n", __FILE__, __LINE__, temp);
+#endif
+
+ stat.rsrv0 = (temp & 0xffffff00) >> 8;
+ stat.mcf = (temp & 0x00000080) >> 7;
+ stat.maas = (temp & 0x00000040) >> 6;
+ stat.mbb = (temp & 0x00000020) >> 5;
+ stat.mal = (temp & 0x00000010) >> 4;
+ stat.rsrv1 = (temp & 0x00000008) >> 3;
+ stat.srw = (temp & 0x00000004) >> 2;
+ stat.mif = (temp & 0x00000002) >> 1;
+ stat.rxak = (temp & 0x00000001);
+ return stat;
+}
+
+/*********************************************
+ * function: I2c_Set_Ctrl
+ *
+ * description: Change I2C Control bits,
+ * i.e., write to I2CCR
+ *
+ ********************************************/
+static void I2C_Set_Ctrl (unsigned int eumbbar, I2C_CTRL ctrl)
+{ /* new control value */
+ unsigned int temp = load_runtime_reg (eumbbar, I2CCR);
+
+ temp &= 0xffffff03;
+ temp |= ((ctrl.men & 0x1) << 7);
+ temp |= ((ctrl.mien & 0x1) << 6);
+ temp |= ((ctrl.msta & 0x1) << 5);
+ temp |= ((ctrl.mtx & 0x1) << 4);
+ temp |= ((ctrl.txak & 0x1) << 3);
+ temp |= ((ctrl.rsta & 0x1) << 2);
+#ifdef I2CDBG0
+ PRINT ("%s(%d): set ctrl = 0x%08x\n", __FILE__, __LINE__, temp);
+#endif
+ store_runtime_reg (eumbbar, I2CCR, temp);
+
+}
+
+/*****************************************
+ * function: I2C_Get_Ctrl
+ *
+ * description: Query I2C Control bits,
+ * i.e., read I2CCR
+ *****************************************/
+static I2C_CTRL I2C_Get_Ctrl (unsigned int eumbbar)
+{
+ union {
+ I2C_CTRL ctrl;
+ unsigned int temp;
+ } s;
+
+ s.temp = load_runtime_reg (eumbbar, I2CCR);
+#ifdef I2CDBG0
+ PRINT ("%s(%d): get ctrl = 0x%08x\n", __FILE__, __LINE__, s.temp);
+#endif
+
+ return s.ctrl;
+}
+
+
+/****************************************
+ * function: I2C_Slave_Addr
+ *
+ * description: Process slave address phase.
+ * return I2CSUCCESS if no error
+ *
+ * note: Precondition for calling this function:
+ * I2CSR(MIF) == 1 &&
+ * I2CSR(MAAS) == 1
+ ****************************************/
+static I2CStatus I2C_Slave_Addr (unsigned int eumbbar)
+{
+ I2C_STAT stat = I2C_Get_Stat (eumbbar);
+ I2C_CTRL ctrl = I2C_Get_Ctrl (eumbbar);
+
+ if (stat.srw == 1) {
+ /* we are asked to xmit */
+ ctrl.mtx = 1;
+ I2C_Set_Ctrl (eumbbar, ctrl); /* set MTX */
+ return I2C_Slave_Xmit (eumbbar);
+ }
+
+ /* we are asked to receive data */
+ ctrl.mtx = 0;
+ I2C_Set_Ctrl (eumbbar, ctrl);
+ (void) load_runtime_reg (eumbbar, I2CDR); /* do a fake read to start */
+
+ return I2CADDRESS;
+}
+
+/***********************************************
+ * function: I2C_ISR
+ *
+ * description: I2C Interrupt service routine
+ *
+ * note: Precondition:
+ * I2CSR(MIF) == 1
+ **********************************************/
+static I2CStatus I2C_ISR (unsigned int eumbbar)
+{
+ I2C_STAT stat;
+ I2C_CTRL ctrl;
+
+#ifdef I2CDBG0
+ PRINT ("%s(%d): I2C_ISR\n", __FILE__, __LINE__);
+#endif
+
+ stat = I2C_Get_Stat (eumbbar);
+ ctrl = I2C_Get_Ctrl (eumbbar);
+
+ /* clear MIF */
+ stat.mif = 0;
+
+ /* Now let see what kind of event this is */
+ if (stat.mcf == 1) {
+ /* transfer compete */
+
+ /* clear the MIF bit */
+ I2C_Set_Stat (eumbbar, stat);
+
+ if (ctrl.msta == 1) {
+ /* master */
+ if (ctrl.mtx == 1) {
+ /* check if this is the address phase for master receive */
+ if (MasterRcvAddress == 1) {
+ /* Yes, it is the address phase of master receive */
+ ctrl.mtx = 0;
+ /* now check how much we want to receive */
+ if (ByteToRcv == 1 && RcvBufFulStop == 1) {
+ ctrl.txak = 1;
+ }
+
+ I2C_Set_Ctrl (eumbbar, ctrl);
+ (void) load_runtime_reg (eumbbar, I2CDR); /* fake read first */
+
+ MasterRcvAddress = 0;
+ return I2CADDRESS;
+
+ }
+
+ /* master xmit */
+ if (stat.rxak == 0) {
+ /* slave has acknowledged */
+ return I2C_Master_Xmit (eumbbar);
+ }
+
+ /* slave has not acknowledged yet, generate a STOP */
+ if (XmitBufEmptyStop == 1) {
+ ctrl.msta = 0;
+ I2C_Set_Ctrl (eumbbar, ctrl);
+ }
+
+ return I2CSUCCESS;
+ }
+
+ /* master receive */
+ return I2C_Master_Rcv (eumbbar);
+ }
+
+ /* slave */
+ if (ctrl.mtx == 1) {
+ /* slave xmit */
+ if (stat.rxak == 0) {
+ /* master has acknowledged */
+ return I2C_Slave_Xmit (eumbbar);
+ }
+
+ /* master has not acknowledged, wait for STOP */
+ /* do nothing for preventing bus from hung */
+ return I2CSUCCESS;
+ }
+
+ /* slave rcv */
+ return I2C_Slave_Rcv (eumbbar);
+
+ } else if (stat.maas == 1) {
+ /* received a call from master */
+
+ /* clear the MIF bit */
+ I2C_Set_Stat (eumbbar, stat);
+
+ /* master is calling us, process the address phase */
+ return I2C_Slave_Addr (eumbbar);
+ } else {
+ /* has to be arbitration lost */
+ stat.mal = 0;
+ I2C_Set_Stat (eumbbar, stat);
+
+ ctrl.msta = 0; /* return to receive mode */
+ I2C_Set_Ctrl (eumbbar, ctrl);
+ }
+
+ return I2CSUCCESS;
+
+}
+
+/******************************************************
+ * function: I2C_Set_Stat
+ *
+ * description: modify the I2CSR
+ *
+ *****************************************************/
+static void I2C_Set_Stat (unsigned int eumbbar, I2C_STAT stat)
+{
+ union {
+ unsigned int val;
+ I2C_STAT stat;
+ } s_tmp;
+ union {
+ unsigned int val;
+ I2C_STAT stat;
+ } s;
+
+ s.val = load_runtime_reg (eumbbar, I2CSR);
+ s.val &= 0xffffff08;
+ s_tmp.stat = stat;
+ s.val |= (s_tmp.val & 0xf7);
+
+#ifdef I2CDBG0
+ PRINT ("%s(%d): set stat = 0x%08x\n", __FILE__, __LINE__, s.val);
+#endif
+
+ store_runtime_reg (eumbbar, I2CSR, s.val);
+
+}
+
+/******************************************************
+ * The following are routines to glue the rest of
+ * U-Boot to the Sandpoint I2C driver.
+ *****************************************************/
+
+void i2c_init (int speed, int slaveadd)
+{
+#ifdef DEBUG
+ I2C_Initialize (0x7f, 0, (void *) printf);
+#else
+ I2C_Initialize (0x7f, 0, 0);
+#endif
+}
+
+int i2c_probe (uchar chip)
+{
+ int tmp;
+
+ /*
+ * Try to read the first location of the chip. The underlying
+ * driver doesn't appear to support sending just the chip address
+ * and looking for an <ACK> back.
+ */
+ udelay(10000);
+ return i2c_read (chip, 0, 1, (char *)&tmp, 1);
+}
+
+int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
+{
+ I2CStatus status;
+ uchar xaddr[4];
+
+ if (alen > 0) {
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+
+ status = I2C_do_buffer (0, I2C_MASTER_XMIT, chip, alen,
+ &xaddr[4 - alen], I2C_NO_STOP, 1,
+ I2C_NO_RESTART);
+ if (status != I2C_SUCCESS) {
+ PRINT ("i2c_read: can't send data address for read\n");
+ return 1;
+ }
+ }
+
+ /* The data transfer will be a continuation. */
+ status = I2C_do_buffer (0, I2C_MASTER_RCV, chip, len,
+ buffer, I2C_STOP, 1, (alen > 0 ? I2C_RESTART :
+ I2C_NO_RESTART));
+
+ if (status != I2C_SUCCESS) {
+ PRINT ("i2c_read: can't perform data transfer\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
+{
+ I2CStatus status;
+ unsigned char dummy_buffer[I2C_RXTX_LEN + 2];
+ int i;
+
+ dummy_buffer[0] = addr & 0xFF;
+ if (alen == 2)
+ dummy_buffer[1] = (addr >> 8) & 0xFF;
+ for (i = 0; i < len; i++)
+ dummy_buffer[i + alen] = buffer[i];
+
+ status = I2C_do_buffer (0, I2C_MASTER_XMIT, chip, alen + len,
+ dummy_buffer, I2C_STOP, 1, I2C_NO_RESTART);
+
+#ifdef CFG_EEPROM_PAGE_WRITE_DELAY_MS
+ udelay(CFG_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
+#endif
+ if (status != I2C_SUCCESS) {
+ PRINT ("i2c_write: can't perform data transfer\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+uchar i2c_reg_read (uchar i2c_addr, uchar reg)
+{
+ char buf[1];
+
+ i2c_init (0, 0);
+
+ i2c_read (i2c_addr, reg, 1, buf, 1);
+
+ return (buf[0]);
+}
+
+void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val)
+{
+ i2c_init (0, 0);
+
+ i2c_write (i2c_addr, reg, 1, &val, 1);
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/cpu/mpc824x/pci.c b/cpu/mpc824x/pci.c
new file mode 100644
index 0000000..7e3c4c3
--- /dev/null
+++ b/cpu/mpc824x/pci.c
@@ -0,0 +1,78 @@
+/*
+ * arch/ppc/kernel/mpc10x_common.c
+ *
+ * Common routines for the Motorola SPS MPC106, MPC107 and MPC8240 Host bridge,
+ * Mem ctlr, EPIC, etc.
+ *
+ * Author: Mark A. Greer
+ * mgreer@mvista.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <mpc824x.h>
+
+void pci_mpc824x_init (struct pci_controller *hose)
+{
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ /* System memory space */
+ pci_set_region(hose->regions + 0,
+ CHRP_PCI_MEMORY_BUS,
+ CHRP_PCI_MEMORY_PHYS,
+ CHRP_PCI_MEMORY_SIZE,
+ PCI_REGION_MEM | PCI_REGION_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 1,
+ CHRP_PCI_MEM_BUS,
+ CHRP_PCI_MEM_PHYS,
+ CHRP_PCI_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ /* ISA/PCI memory space */
+ pci_set_region(hose->regions + 2,
+ CHRP_ISA_MEM_BUS,
+ CHRP_ISA_MEM_PHYS,
+ CHRP_ISA_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ /* PCI I/O space */
+ pci_set_region(hose->regions + 3,
+ CHRP_PCI_IO_BUS,
+ CHRP_PCI_IO_PHYS,
+ CHRP_PCI_IO_SIZE,
+ PCI_REGION_IO);
+
+ /* ISA/PCI I/O space */
+ pci_set_region(hose->regions + 4,
+ CHRP_ISA_IO_BUS,
+ CHRP_ISA_IO_PHYS,
+ CHRP_ISA_IO_SIZE,
+ PCI_REGION_IO);
+
+ hose->region_count = 5;
+
+ pci_setup_indirect(hose,
+ CHRP_REG_ADDR,
+ CHRP_REG_DATA);
+
+ pci_register_hose(hose);
+
+ hose->last_busno = pci_hose_scan(hose);
+}
+
+#endif
diff --git a/cpu/mpc824x/start.S b/cpu/mpc824x/start.S
new file mode 100644
index 0000000..bd9706d
--- /dev/null
+++ b/cpu/mpc824x/start.S
@@ -0,0 +1,835 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000,2001,2002 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* U-Boot - Startup Code for PowerPC based Embedded Boards
+ *
+ *
+ * The processor starts at 0x00000100 and the code is executed
+ * from flash. The code is organized to be at an other address
+ * in memory, but as long we don't jump around before relocating.
+ * board_init lies at a quite high address and when the cpu has
+ * jumped there, everything is ok.
+ * This works because the cpu gives the FLASH (CS0) the whole
+ * address space at startup, and board_init lies as a echo of
+ * the flash somewhere up there in the memorymap.
+ *
+ * board_init will change CS0 to be positioned at the correct
+ * address and (s)dram will be positioned at address 0
+ */
+#include <config.h>
+#include <mpc824x.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
+/* FP, Machine Check and Recoverable Interr. */
+#define MSR_KERNEL ( MSR_FP | MSR_ME | MSR_RI )
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r14 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(_end)
+ GOT_ENTRY(.bss)
+#if defined(CONFIG_FADS)
+ GOT_ENTRY(environment)
+#endif
+ END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+ .text
+ .long 0x27051956 /* U-Boot Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION
+ .ascii " (", __DATE__, " - ", __TIME__, ")"
+ .ascii CONFIG_IDENT_STRING, "\0"
+
+ . = EXC_OFF_SYS_RESET
+ .globl _start
+_start:
+ li r21, BOOTFLAG_COLD /* Normal Power-On: Boot from FLASH */
+ b boot_cold
+
+ . = EXC_OFF_SYS_RESET + 0x10
+
+ .globl _start_warm
+_start_warm:
+ li r21, BOOTFLAG_WARM /* Software reboot */
+ b boot_warm
+
+boot_cold:
+boot_warm:
+
+ /* Initialize machine status; enable machine check interrupt */
+ /*----------------------------------------------------------------------*/
+ li r3, MSR_KERNEL /* Set FP, ME, RI flags */
+ mtmsr r3
+ mtspr SRR1, r3 /* Make SRR1 match MSR */
+
+ addis r0,0,0x0000 /* lets make sure that r0 is really 0 */
+ mtspr HID0, r0 /* disable I and D caches */
+
+ mfspr r3, ICR /* clear Interrupt Cause Register */
+
+ mfmsr r3 /* turn off address translation */
+ addis r4,0,0xffff
+ ori r4,r4,0xffcf
+ and r3,r3,r4
+ mtmsr r3
+ isync
+ sync /* the MMU should be off... */
+
+
+in_flash:
+#if defined(CONFIG_BMW)
+ bl early_init_f /* Must be ASM: no stack yet! */
+#endif
+ /*
+ * Setup BATs - cannot be done in C since we don't have a stack yet
+ */
+ bl setup_bats
+
+ /* Enable MMU.
+ */
+ mfmsr r3
+ ori r3, r3, (MSR_IR | MSR_DR)
+ mtmsr r3
+#if !defined(CONFIG_BMW)
+ /* Enable and invalidate data cache.
+ */
+ mfspr r3, HID0
+ mr r2, r3
+ ori r3, r3, HID0_DCE | HID0_DCI
+ ori r2, r2, HID0_DCE
+ sync
+ mtspr HID0, r3
+ mtspr HID0, r2
+ sync
+
+ /* Allocate Initial RAM in data cache.
+ */
+ lis r3, CFG_INIT_RAM_ADDR@h
+ ori r3, r3, CFG_INIT_RAM_ADDR@l
+ li r2, 128
+ mtctr r2
+1:
+ dcbz r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+
+ /* Lock way0 in data cache.
+ */
+ mfspr r3, 1011
+ lis r2, 0xffff
+ ori r2, r2, 0xff1f
+ and r3, r3, r2
+ ori r3, r3, 0x0080
+ sync
+ mtspr 1011, r3
+#endif /* !CONFIG_BMW */
+ /*
+ * Thisk the stack pointer *somewhere* sensible. Doesnt
+ * matter much where as we'll move it when we relocate
+ */
+ lis r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@h
+ ori r1, r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@l
+
+ 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 (from Flash) */
+
+ mr r3, r21
+ /* r3: BOOTFLAG */
+ bl board_init_f /* run 1st part of board init code (from Flash) */
+
+
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(EXC_OFF_MACH_CHCK, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. "Never" generated on the 860. */
+ STD_EXCEPTION(EXC_OFF_DATA_STOR, DataStorage, UnknownException)
+
+/* Instruction Storage exception. "Never" generated on the 860. */
+ STD_EXCEPTION(EXC_OFF_INS_STOR, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(EXC_OFF_EXTERNAL, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = EXC_OFF_ALIGN
+Alignment:
+ EXCEPTION_PROLOG
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ lwz r6,GOT(transfer_to_handler)
+ mtlr r6
+ blrl
+.L_Alignment:
+ .long AlignmentException - _start + EXC_OFF_SYS_RESET
+ .long int_return - _start + EXC_OFF_SYS_RESET
+
+/* Program check exception */
+ . = EXC_OFF_PROGRAM
+ProgramCheck:
+ EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ lwz r6,GOT(transfer_to_handler)
+ mtlr r6
+ blrl
+.L_ProgramCheck:
+ .long ProgramCheckException - _start + EXC_OFF_SYS_RESET
+ .long int_return - _start + EXC_OFF_SYS_RESET
+
+ /* No FPU on MPC8xx. This exception is not supposed to happen.
+ */
+ STD_EXCEPTION(EXC_OFF_FPUNAVAIL, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(EXC_OFF_DECR, Decrementer, timer_interrupt)
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+
+ . = 0xc00
+/*
+ * r0 - SYSCALL number
+ * r3-... arguments
+ */
+SystemCall:
+ addis r11,r0,0 /* get functions table addr */
+ ori r11,r11,0 /* Note: this code is patched in trap_init */
+ addis r12,r0,0 /* get number of functions */
+ ori r12,r12,0
+
+ cmplw 0, r0, r12
+ bge 1f
+
+ rlwinm r0,r0,2,0,31 /* fn_addr = fn_tbl[r0] */
+ add r11,r11,r0
+ lwz r11,0(r11)
+
+ li r12,0xd00-4*3 /* save LR & SRRx */
+ mflr r0
+ stw r0,0(r12)
+ mfspr r0,SRR0
+ stw r0,4(r12)
+ mfspr r0,SRR1
+ stw r0,8(r12)
+
+ li r12,0xc00+_back-SystemCall
+ mtlr r12
+ mtspr SRR0,r11
+
+1: SYNC
+ rfi
+
+_back:
+
+ mfmsr r11 /* Disable interrupts */
+ li r12,0
+ ori r12,r12,MSR_EE
+ andc r11,r11,r12
+ SYNC /* Some chip revs need this... */
+ mtmsr r11
+ SYNC
+
+ li r12,0xd00-4*3 /* restore regs */
+ lwz r11,0(r12)
+ mtlr r11
+ lwz r11,4(r12)
+ mtspr SRR0,r11
+ lwz r11,8(r12)
+ mtspr SRR1,r11
+
+ SYNC
+ rfi
+
+ STD_EXCEPTION(EXC_OFF_TRACE, SingleStep, UnknownException)
+
+ STD_EXCEPTION(EXC_OFF_FPUNASSIST, Trap_0e, UnknownException)
+ STD_EXCEPTION(EXC_OFF_PMI, Trap_0f, UnknownException)
+
+ STD_EXCEPTION(EXC_OFF_ITME, InstructionTransMiss, UnknownException)
+ STD_EXCEPTION(EXC_OFF_DLTME, DataLoadTransMiss, UnknownException)
+ STD_EXCEPTION(EXC_OFF_DSTME, DataStoreTransMiss, UnknownException)
+ STD_EXCEPTION(EXC_OFF_IABE, InstructionBreakpoint, UnknownException)
+ STD_EXCEPTION(EXC_OFF_SMIE, SysManageInt, UnknownException)
+ STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+ STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+ STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+ STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+ STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+ STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+ STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+ STD_EXCEPTION(0x1c00, ReservedC, UnknownException)
+ STD_EXCEPTION(0x1d00, ReservedD, UnknownException)
+ STD_EXCEPTION(0x1e00, ReservedE, UnknownException)
+ STD_EXCEPTION(0x1f00, ReservedF, UnknownException)
+
+ STD_EXCEPTION(EXC_OFF_RMTE, RunModeTrace, 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)
+#if 0
+ andi. r23,r23,MSR_PR
+ mfspr r23,SPRG3 /* if from user, fix up tss.regs */
+ beq 2f
+ addi r24,r1,STACK_FRAME_OVERHEAD
+ stw r24,PT_REGS(r23)
+2: addi r2,r23,-TSS /* set r2 to current */
+ tovirt(r2,r2,r23)
+#endif
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ mtspr SPRG2,r22 /* r1 is now kernel sp */
+#if 0
+ addi r24,r2,TASK_STRUCT_SIZE /* check for kernel stack overflow */
+ cmplw 0,r1,r2
+ cmplw 1,r1,r24
+ crand 1,1,4
+ bgt stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */
+#endif
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ ori r20,r20,0x30 /* enable IR, DR */
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+/* Cache functions.
+*/
+ .globl icache_enable
+icache_enable:
+ mfspr r5,HID0 /* turn on the I cache. */
+ ori r5,r5,0x8800 /* Instruction cache only! */
+ addis r6,0,0xFFFF
+ ori r6,r6,0xF7FF
+ and r6,r5,r6 /* clear the invalidate bit */
+ sync
+ mtspr HID0,r5
+ mtspr HID0,r6
+ isync
+ sync
+ blr
+
+ .globl icache_disable
+icache_disable:
+ mfspr r5,HID0
+ addis r6,0,0xFFFF
+ ori r6,r6,0x7FFF
+ and r5,r5,r6
+ sync
+ mtspr HID0,r5
+ isync
+ sync
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3, HID0
+ srwi r3, r3, 15 /* >>15 & 1=> select bit 16 */
+ andi. r3, r3, 1
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+ mfspr r5,HID0 /* turn on the D cache. */
+ ori r5,r5,0x4400 /* Data cache only! */
+ mfspr r4, PVR /* read PVR */
+ srawi r3, r4, 16 /* shift off the least 16 bits */
+ cmpi 0, 0, r3, 0xC /* Check for Max pvr */
+ bne NotMax
+ ori r5,r5,0x0040 /* setting the DCFA bit, for Max rev 1 errata */
+NotMax:
+ addis r6,0,0xFFFF
+ ori r6,r6,0xFBFF
+ and r6,r5,r6 /* clear the invalidate bit */
+ sync
+ mtspr HID0,r5
+ mtspr HID0,r6
+ isync
+ sync
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mfspr r5,HID0
+ addis r6,0,0xFFFF
+ ori r6,r6,0xBFFF
+ and r5,r5,r6
+ sync
+ mtspr HID0,r5
+ isync
+ sync
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3, HID0
+ srwi r3, r3, 14 /* >>14 & 1=> select bit 17 */
+ andi. r3, r3, 1
+ blr
+
+ .globl dc_read
+dc_read:
+/*TODO : who uses this, what should it do?
+*/
+ 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 */
+
+ mr r3, r5 /* Destination Address */
+#ifdef DEBUG
+ lis r4, CFG_SDRAM_BASE@h /* Source Address */
+ ori r4, r4, CFG_SDRAM_BASE@l
+#else
+ lis r4, CFG_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CFG_MONITOR_BASE@l
+#endif
+ lis r5, CFG_MONITOR_LEN@h /* Length in Bytes */
+ ori r5, r5, CFG_MONITOR_LEN@l
+ li r6, CFG_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r14, r14, r15
+ /* the the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+
+ /*
+ * Relocation Function, r14 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)
+ add r0,r0,r11
+ stw r0,0(r3)
+ bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+2: 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)
+ 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
+ blt 5b
+6:
+
+ mr r3, r9 /* Global Data pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+ /* Problems accessing "end" in C, so do it here */
+ .globl get_endaddr
+get_endaddr:
+ lwz r3,GOT(_end)
+ blr
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ rlwinm r9, r7, 0, 18, 31 /* _start & 0x3FFF */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+
+ mflr r4 /* save link register */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ mtlr r4 /* restore link register */
+ blr
+
+ /*
+ * Function: relocate entries for one exception vector
+ */
+trap_reloc:
+ lwz r0, 0(r7) /* hdlr ... */
+ add r0, r0, r3 /* ... += dest_addr */
+ stw r0, 0(r7)
+
+ lwz r0, 4(r7) /* int_return ... */
+ add r0, r0, r3 /* ... += dest_addr */
+ stw r0, 4(r7)
+
+ blr
+
+ /* Setup the BAT registers.
+ */
+setup_bats:
+ lis r4, CFG_IBAT0L@h
+ ori r4, r4, CFG_IBAT0L@l
+ lis r3, CFG_IBAT0U@h
+ ori r3, r3, CFG_IBAT0U@l
+ mtspr IBAT0L, r4
+ mtspr IBAT0U, r3
+ isync
+
+ lis r4, CFG_DBAT0L@h
+ ori r4, r4, CFG_DBAT0L@l
+ lis r3, CFG_DBAT0U@h
+ ori r3, r3, CFG_DBAT0U@l
+ mtspr DBAT0L, r4
+ mtspr DBAT0U, r3
+ isync
+
+ lis r4, CFG_IBAT1L@h
+ ori r4, r4, CFG_IBAT1L@l
+ lis r3, CFG_IBAT1U@h
+ ori r3, r3, CFG_IBAT1U@l
+ mtspr IBAT1L, r4
+ mtspr IBAT1U, r3
+ isync
+
+ lis r4, CFG_DBAT1L@h
+ ori r4, r4, CFG_DBAT1L@l
+ lis r3, CFG_DBAT1U@h
+ ori r3, r3, CFG_DBAT1U@l
+ mtspr DBAT1L, r4
+ mtspr DBAT1U, r3
+ isync
+
+ lis r4, CFG_IBAT2L@h
+ ori r4, r4, CFG_IBAT2L@l
+ lis r3, CFG_IBAT2U@h
+ ori r3, r3, CFG_IBAT2U@l
+ mtspr IBAT2L, r4
+ mtspr IBAT2U, r3
+ isync
+
+ lis r4, CFG_DBAT2L@h
+ ori r4, r4, CFG_DBAT2L@l
+ lis r3, CFG_DBAT2U@h
+ ori r3, r3, CFG_DBAT2U@l
+ mtspr DBAT2L, r4
+ mtspr DBAT2U, r3
+ isync
+
+ lis r4, CFG_IBAT3L@h
+ ori r4, r4, CFG_IBAT3L@l
+ lis r3, CFG_IBAT3U@h
+ ori r3, r3, CFG_IBAT3U@l
+ mtspr IBAT3L, r4
+ mtspr IBAT3U, r3
+ isync
+
+ lis r4, CFG_DBAT3L@h
+ ori r4, r4, CFG_DBAT3L@l
+ lis r3, CFG_DBAT3U@h
+ ori r3, r3, CFG_DBAT3U@l
+ mtspr DBAT3L, r4
+ mtspr DBAT3U, r3
+ isync
+
+ /* Invalidate TLBs.
+ * -> for (val = 0; val < 0x20000; val+=0x1000)
+ * -> tlbie(val);
+ */
+ lis r3, 0
+ lis r5, 2
+
+1:
+ tlbie r3
+ addi r3, r3, 0x1000
+ cmp 0, 0, r3, r5
+ blt 1b
+
+ blr
+
+