diff options
author | Stefan Roese <sr@denx.de> | 2010-04-15 16:07:28 +0200 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2010-04-21 23:42:38 +0200 |
commit | a47a12becf66f02a56da91c161e2edb625e9f20c (patch) | |
tree | 6efae7137d26d1e610c5fd56b7aaa3c043ad2b71 /arch/powerpc/cpu/mpc824x | |
parent | 254ab7bd464657600aba69d840406f9358f3e116 (diff) | |
download | u-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/mpc824x')
20 files changed, 3800 insertions, 0 deletions
diff --git a/arch/powerpc/cpu/mpc824x/.gitignore b/arch/powerpc/cpu/mpc824x/.gitignore new file mode 100644 index 0000000..2d79931 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/.gitignore @@ -0,0 +1 @@ +/bedbug_603e.c diff --git a/arch/powerpc/cpu/mpc824x/Makefile b/arch/powerpc/cpu/mpc824x/Makefile new file mode 100644 index 0000000..a57ad12 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/Makefile @@ -0,0 +1,56 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk +ifneq ($(OBJTREE),$(SRCTREE)) +$(shell mkdir -p $(obj)drivers/epic) +$(shell mkdir -p $(obj)drivers/i2c) +endif + +LIB = $(obj)lib$(CPU).a + +START = start.o +COBJS = traps.o cpu.o cpu_init.o interrupts.o speed.o \ + drivers/epic/epic1.o drivers/i2c/i2c.o pci.o +COBJS_LN = bedbug_603e.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) $(addprefix $(obj),$(COBJS_LN:.o=.c)) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS) $(COBJS_LN)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +$(obj)bedbug_603e.c: + ln -sf $(src)../mpc8260/bedbug_603e.c $(obj)bedbug_603e.c + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/powerpc/cpu/mpc824x/config.mk b/arch/powerpc/cpu/mpc824x/config.mk new file mode 100644 index 0000000..27c2873 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/config.mk @@ -0,0 +1,29 @@ +# +# (C) Copyright 2000 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +PLATFORM_RELFLAGS += -fPIC -meabi + +PLATFORM_CPPFLAGS += -DCONFIG_MPC824X -ffixed-r2 -mstring -mcpu=603e -msoft-float + +# Use default linker script. Board port can override in board/*/config.mk +LDSCRIPT := $(SRCTREE)/arch/powerpc/cpu/mpc824x/u-boot.lds diff --git a/arch/powerpc/cpu/mpc824x/cpu.c b/arch/powerpc/cpu/mpc824x/cpu.c new file mode 100644 index 0000000..08f6a94 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/cpu.c @@ -0,0 +1,280 @@ +/* + * (C) Copyright 2000 - 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <config.h> +#include <mpc824x.h> +#include <common.h> +#include <command.h> + +DECLARE_GLOBAL_DATA_PTR; + +int checkcpu (void) +{ + unsigned int pvr = get_pvr (); + unsigned int version = pvr >> 16; + unsigned char revision; + ulong clock = gd->cpu_clk; + char buf[32]; + + puts ("CPU: "); + + switch (version) { + case CPU_TYPE_8240: + puts ("MPC8240"); + break; + + case CPU_TYPE_8245: + puts ("MPC8245"); + break; + + default: + return -1; /*not valid for this source */ + } + + CONFIG_READ_BYTE (REVID, revision); + + if (revision) { + printf (" Revision %d.%d", + (revision & 0xf0) >> 4, + (revision & 0x0f)); + } else { + return -1; /* no valid CPU revision info */ + } + + printf (" at %s MHz:", strmhz (buf, clock)); + + printf (" %u kB I-Cache", checkicache () >> 10); + printf (" %u kB D-Cache", checkdcache () >> 10); + + puts ("\n"); + + return 0; +} + +/* ------------------------------------------------------------------------- */ +/* L1 i-cache */ + +int checkicache (void) +{ + /*TODO*/ + return 128 * 4 * 32; +}; + +/* ------------------------------------------------------------------------- */ +/* L1 d-cache */ + +int checkdcache (void) +{ + /*TODO*/ + return 128 * 4 * 32; + +}; + +/*------------------------------------------------------------------- */ + +int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong msr, addr; + + /* Interrupts and MMU off */ + __asm__ ("mtspr 81, 0"); + + /* Interrupts and MMU off */ + __asm__ __volatile__ ("mfmsr %0":"=r" (msr):); + + msr &= ~0x1030; + __asm__ __volatile__ ("mtmsr %0"::"r" (msr)); + + /* + * Trying to execute the next instruction at a non-existing address + * should cause a machine check, resulting in reset + */ +#ifdef CONFIG_SYS_RESET_ADDRESS + addr = CONFIG_SYS_RESET_ADDRESS; +#else + /* + * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, + * CONFIG_SYS_MONITOR_BASE - sizeof (ulong) is usually a valid + * address. Better pick an address known to be invalid on + * your system and assign it to CONFIG_SYS_RESET_ADDRESS. + * "(ulong)-1" used to be a good choice for many systems... + */ + addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong); +#endif + ((void (*)(void)) addr) (); + return 1; + +} + +/* ------------------------------------------------------------------------- */ + +/* + * Get timebase clock frequency (like cpu_clk in Hz) + * This is the sys_logic_clk (memory bus) divided by 4 + */ +unsigned long get_tbclk (void) +{ + return ((get_bus_freq (0) + 2L) / 4L); +} + +/* ------------------------------------------------------------------------- */ + +/* + * The MPC824x has an integrated PCI controller known as the MPC107. + * The following are MPC107 Bridge Controller and PCI Support functions + * + */ + +/* + * This procedure reads a 32-bit address MPC107 register, and returns + * a 32 bit value. It swaps the address to little endian before + * writing it to config address, and swaps the value to big endian + * before returning to the caller. + */ +unsigned int mpc824x_mpc107_getreg (unsigned int regNum) +{ + unsigned int temp; + + /* swap the addr. to little endian */ + *(volatile unsigned int *) CHRP_REG_ADDR = PCISWAP (regNum); + temp = *(volatile unsigned int *) CHRP_REG_DATA; + return PCISWAP (temp); /* swap the data upon return */ +} + +/* + * This procedure writes a 32-bit address MPC107 register. It swaps + * the address to little endian before writing it to config address. + */ + +void mpc824x_mpc107_setreg (unsigned int regNum, unsigned int regVal) +{ + /* swap the addr. to little endian */ + *(volatile unsigned int *) CHRP_REG_ADDR = PCISWAP (regNum); + *(volatile unsigned int *) CHRP_REG_DATA = PCISWAP (regVal); + return; +} + + +/* + * Write a byte (8 bits) to a memory location. + */ +void mpc824x_mpc107_write8 (unsigned int addr, unsigned char data) +{ + *(unsigned char *) addr = data; + __asm__ ("sync"); +} + +/* + * Write a word (16 bits) to a memory location after the value + * has been byte swapped (big to little endian or vice versa) + */ + +void mpc824x_mpc107_write16 (unsigned int address, unsigned short data) +{ + *(volatile unsigned short *) address = BYTE_SWAP_16_BIT (data); + __asm__ ("sync"); +} + +/* + * Write a long word (32 bits) to a memory location after the value + * has been byte swapped (big to little endian or vice versa) + */ + +void mpc824x_mpc107_write32 (unsigned int address, unsigned int data) +{ + *(volatile unsigned int *) address = LONGSWAP (data); + __asm__ ("sync"); +} + +/* + * Read a byte (8 bits) from a memory location. + */ +unsigned char mpc824x_mpc107_read8 (unsigned int addr) +{ + return *(volatile unsigned char *) addr; +} + + +/* + * Read a word (16 bits) from a memory location, and byte swap the + * value before returning to the caller. + */ +unsigned short mpc824x_mpc107_read16 (unsigned int address) +{ + unsigned short retVal; + + retVal = BYTE_SWAP_16_BIT (*(unsigned short *) address); + return retVal; +} + + +/* + * Read a long word (32 bits) from a memory location, and byte + * swap the value before returning to the caller. + */ +unsigned int mpc824x_mpc107_read32 (unsigned int address) +{ + unsigned int retVal; + + retVal = LONGSWAP (*(unsigned int *) address); + return (retVal); +} + + +/* + * Read a register in the Embedded Utilities Memory Block address + * space. + * Input: regNum - register number + utility base address. Example, + * the base address of EPIC is 0x40000, the register number + * being passed is 0x40000+the address of the target register. + * (See epic.h for register addresses). + * Output: The 32 bit little endian value of the register. + */ + +unsigned int mpc824x_eummbar_read (unsigned int regNum) +{ + unsigned int temp; + + temp = *(volatile unsigned int *) (EUMBBAR_VAL + regNum); + temp = PCISWAP (temp); + return temp; +} + + +/* + * Write a value to a register in the Embedded Utilities Memory + * Block address space. + * Input: regNum - register number + utility base address. Example, + * the base address of EPIC is 0x40000, the register + * number is 0x40000+the address of the target register. + * (See epic.h for register addresses). + * regVal - value to be written to the register. + */ + +void mpc824x_eummbar_write (unsigned int regNum, unsigned int regVal) +{ + *(volatile unsigned int *) (EUMBBAR_VAL + regNum) = PCISWAP (regVal); + return; +} + +/* ------------------------------------------------------------------------- */ diff --git a/arch/powerpc/cpu/mpc824x/cpu_init.c b/arch/powerpc/cpu/mpc824x/cpu_init.c new file mode 100644 index 0000000..395f776 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/cpu_init.c @@ -0,0 +1,417 @@ +/* + * (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 CONFIG_SYS_BANK0_ROW +#define CONFIG_SYS_BANK0_ROW 0 +#endif +#ifndef CONFIG_SYS_BANK1_ROW +#define CONFIG_SYS_BANK1_ROW 0 +#endif +#ifndef CONFIG_SYS_BANK2_ROW +#define CONFIG_SYS_BANK2_ROW 0 +#endif +#ifndef CONFIG_SYS_BANK3_ROW +#define CONFIG_SYS_BANK3_ROW 0 +#endif +#ifndef CONFIG_SYS_BANK4_ROW +#define CONFIG_SYS_BANK4_ROW 0 +#endif +#ifndef CONFIG_SYS_BANK5_ROW +#define CONFIG_SYS_BANK5_ROW 0 +#endif +#ifndef CONFIG_SYS_BANK6_ROW +#define CONFIG_SYS_BANK6_ROW 0 +#endif +#ifndef CONFIG_SYS_BANK7_ROW +#define CONFIG_SYS_BANK7_ROW 0 +#endif +#ifndef CONFIG_SYS_DBUS_SIZE2 +#define CONFIG_SYS_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 */ + CONFIG_WRITE_BYTE (PLTR, 0x40); /* set PCI latency timer */ + /* + * 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); +#ifdef CONFIG_MPC8245 + /* silicon bug 28 MPC8245 */ + CONFIG_READ_BYTE(AMBOR,val); + CONFIG_WRITE_BYTE(AMBOR,val|0x1); + +#if 0 + /* + * The following bug only affects older (XPC8245) processors. + * DMA transfers initiated by external devices get corrupted due + * to a hardware scheduling problem. + * + * The effect is: + * when transferring X words, the first 32 words are transferred + * OK, the next 3 x 32 words are 'old' data (from previous DMA) + * while the rest of the X words is xferred fine. + * + * Disabling 3 of the 4 32 word hardware buffers solves the problem + * with no significant performance loss. + */ + + CONFIG_READ_BYTE(PCMBCR,val); + /* in order not to corrupt data which is being read over the PCI bus + * with the PPC as slave, we need to reduce the number of PCMRBs to 1, + * 4.11 in the processor user manual + * */ + +#if 1 + CONFIG_WRITE_BYTE(PCMBCR,(val|0xC0)); /* 1 PCMRB */ +#else + CONFIG_WRITE_BYTE(PCMBCR,(val|0x80)); /* 2 PCMRBs */ + CONFIG_WRITE_BYTE(PCMBCR,(val|0x40)); /* 3 PCMRBs */ + /* default, 4 PCMRBs are used */ +#endif +#endif +#endif + + 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, CONFIG_SYS_EUMB_ADDR); +#ifndef CONFIG_SYS_RAMBOOT + CONFIG_WRITE_WORD(MCCR1, (CONFIG_SYS_ROMNAL << MCCR1_ROMNAL_SHIFT) | + (CONFIG_SYS_BANK0_ROW) | + (CONFIG_SYS_BANK1_ROW << MCCR1_BANK1ROW_SHIFT) | + (CONFIG_SYS_BANK2_ROW << MCCR1_BANK2ROW_SHIFT) | + (CONFIG_SYS_BANK3_ROW << MCCR1_BANK3ROW_SHIFT) | + (CONFIG_SYS_BANK4_ROW << MCCR1_BANK4ROW_SHIFT) | + (CONFIG_SYS_BANK5_ROW << MCCR1_BANK5ROW_SHIFT) | + (CONFIG_SYS_BANK6_ROW << MCCR1_BANK6ROW_SHIFT) | + (CONFIG_SYS_BANK7_ROW << MCCR1_BANK7ROW_SHIFT) | + (CONFIG_SYS_ROMFAL << MCCR1_ROMFAL_SHIFT)); +#endif + +#if defined(CONFIG_SYS_ASRISE) && defined(CONFIG_SYS_ASFALL) + CONFIG_WRITE_WORD(MCCR2, CONFIG_SYS_REFINT << MCCR2_REFINT_SHIFT | + CONFIG_SYS_ASRISE << MCCR2_ASRISE_SHIFT | + CONFIG_SYS_ASFALL << MCCR2_ASFALL_SHIFT); +#else + CONFIG_WRITE_WORD(MCCR2, CONFIG_SYS_REFINT << MCCR2_REFINT_SHIFT); +#endif + +#if defined(CONFIG_MPC8240) + CONFIG_WRITE_WORD(MCCR3, + (((CONFIG_SYS_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) | + (CONFIG_SYS_REFREC << MCCR3_REFREC_SHIFT) | + (CONFIG_SYS_RDLAT << MCCR3_RDLAT_SHIFT)); +#elif defined(CONFIG_MPC8245) + CONFIG_WRITE_WORD(MCCR3, + (((CONFIG_SYS_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) | + (CONFIG_SYS_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 CONFIG_SYS_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, + (CONFIG_SYS_PRETOACT << MCCR4_PRETOACT_SHIFT) | + (CONFIG_SYS_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) | + MCCR4_BIT21 | + (CONFIG_SYS_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) | + ((CONFIG_SYS_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) | + (((CONFIG_SYS_SDMODE_CAS_LAT <<4) | (CONFIG_SYS_SDMODE_WRAP <<3) | + CONFIG_SYS_SDMODE_BURSTLEN) << MCCR4_SDMODE_SHIFT) | + (CONFIG_SYS_ACTORW << MCCR4_ACTTORW_SHIFT) | + (((CONFIG_SYS_BSTOPRE & 0x03c0) >> 6) << MCCR4_BSTOPRE6TO9_SHIFT)); +#elif defined(CONFIG_MPC8240) + CONFIG_WRITE_WORD(MCCR4, + (CONFIG_SYS_PRETOACT << MCCR4_PRETOACT_SHIFT) | + (CONFIG_SYS_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) | + MCCR4_BIT21 | + (CONFIG_SYS_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) | + ((CONFIG_SYS_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) | + (((CONFIG_SYS_SDMODE_CAS_LAT <<4) | (CONFIG_SYS_SDMODE_WRAP <<3) | + (CONFIG_SYS_SDMODE_BURSTLEN)) <<MCCR4_SDMODE_SHIFT) | + (((CONFIG_SYS_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, + (CONFIG_SYS_PRETOACT << MCCR4_PRETOACT_SHIFT) | + (CONFIG_SYS_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) | + (CONFIG_SYS_EXTROM ? MCCR4_EXTROM : 0) | + (CONFIG_SYS_REGDIMM ? MCCR4_REGDIMM : 0) | + (CONFIG_SYS_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) | + ((CONFIG_SYS_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) | + (CONFIG_SYS_DBUS_SIZE2 << MCCR4_DBUS_SIZE2_SHIFT) | + (((CONFIG_SYS_SDMODE_CAS_LAT <<4) | (CONFIG_SYS_SDMODE_WRAP <<3) | + (val ? 2 : 3)) << MCCR4_SDMODE_SHIFT) | + (CONFIG_SYS_ACTORW << MCCR4_ACTTORW_SHIFT) | + (((CONFIG_SYS_BSTOPRE & 0x03c0) >> 6) <<MCCR4_BSTOPRE6TO9_SHIFT )); +#else +#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240) +#endif + + CONFIG_WRITE_WORD(MSAR1, + ( (CONFIG_SYS_BANK0_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) | + (((CONFIG_SYS_BANK1_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) | + (((CONFIG_SYS_BANK2_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | + (((CONFIG_SYS_BANK3_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24)); + CONFIG_WRITE_WORD(EMSAR1, + ( (CONFIG_SYS_BANK0_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) | + (((CONFIG_SYS_BANK1_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) | + (((CONFIG_SYS_BANK2_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | + (((CONFIG_SYS_BANK3_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24)); + CONFIG_WRITE_WORD(MSAR2, + ( (CONFIG_SYS_BANK4_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) | + (((CONFIG_SYS_BANK5_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) | + (((CONFIG_SYS_BANK6_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | + (((CONFIG_SYS_BANK7_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24)); + CONFIG_WRITE_WORD(EMSAR2, + ( (CONFIG_SYS_BANK4_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) | + (((CONFIG_SYS_BANK5_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) | + (((CONFIG_SYS_BANK6_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | + (((CONFIG_SYS_BANK7_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24)); + CONFIG_WRITE_WORD(MEAR1, + ( (CONFIG_SYS_BANK0_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) | + (((CONFIG_SYS_BANK1_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) | + (((CONFIG_SYS_BANK2_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | + (((CONFIG_SYS_BANK3_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24)); + CONFIG_WRITE_WORD(EMEAR1, + ( (CONFIG_SYS_BANK0_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) | + (((CONFIG_SYS_BANK1_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) | + (((CONFIG_SYS_BANK2_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | + (((CONFIG_SYS_BANK3_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24)); + CONFIG_WRITE_WORD(MEAR2, + ( (CONFIG_SYS_BANK4_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) | + (((CONFIG_SYS_BANK5_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) | + (((CONFIG_SYS_BANK6_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | + (((CONFIG_SYS_BANK7_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24)); + CONFIG_WRITE_WORD(EMEAR2, + ( (CONFIG_SYS_BANK4_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) | + (((CONFIG_SYS_BANK5_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) | + (((CONFIG_SYS_BANK6_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | + (((CONFIG_SYS_BANK7_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24)); + + CONFIG_WRITE_BYTE(ODCR, CONFIG_SYS_ODCR); +#ifdef CONFIG_SYS_DLL_MAX_DELAY + CONFIG_WRITE_BYTE(MIOCR1, CONFIG_SYS_DLL_MAX_DELAY); /* needed to make DLL lock */ +#endif +#if defined(CONFIG_SYS_DLL_EXTEND) && defined(CONFIG_SYS_PCI_HOLD_DEL) + CONFIG_WRITE_BYTE(PMCR2, CONFIG_SYS_DLL_EXTEND | CONFIG_SYS_PCI_HOLD_DEL); +#endif +#if defined(MIOCR2) && defined(CONFIG_SYS_SDRAM_DSCD) + CONFIG_WRITE_BYTE(MIOCR2, CONFIG_SYS_SDRAM_DSCD); /* change memory input */ +#endif /* setup & hold time */ + + CONFIG_WRITE_BYTE(MBER, + CONFIG_SYS_BANK0_ENABLE | + (CONFIG_SYS_BANK1_ENABLE << 1) | + (CONFIG_SYS_BANK2_ENABLE << 2) | + (CONFIG_SYS_BANK3_ENABLE << 3) | + (CONFIG_SYS_BANK4_ENABLE << 4) | + (CONFIG_SYS_BANK5_ENABLE << 5) | + (CONFIG_SYS_BANK6_ENABLE << 6) | + (CONFIG_SYS_BANK7_ENABLE << 7)); + +#ifdef CONFIG_SYS_PGMAX + CONFIG_WRITE_BYTE(MPMR, CONFIG_SYS_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 + 0x00, "MPC107 Vendor/Device ID" }, + { BMC_BASE + 0x04, "MPC107 PCI Command/Status Register" }, + { BMC_BASE + 0x08, "MPC107 Revision" }, + { BMC_BASE + 0x0C, "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/arch/powerpc/cpu/mpc824x/drivers/epic.h b/arch/powerpc/cpu/mpc824x/drivers/epic.h new file mode 100644 index 0000000..2803f63 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/drivers/epic.h @@ -0,0 +1 @@ +#include "epic/epic.h" diff --git a/arch/powerpc/cpu/mpc824x/drivers/epic/README b/arch/powerpc/cpu/mpc824x/drivers/epic/README new file mode 100644 index 0000000..5798996 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/drivers/epic/README @@ -0,0 +1,102 @@ +CONTENT: + + epic.h + epic1.c + epic2.s + +WHAT ARE THESE FILES: + +These files contain MPC8240 (Kahlua) EPIC +driver routines. The driver routines are not +written for any specific operating system. +They serves the purpose of code sample, and +jump-start for using the MPC8240 EPIC unit. + +For the reason of correctness of C language +syntax, these files are compiled by Metaware +C compiler and assembler. + +ENDIAN NOTATION: + +The algorithm is designed for big-endian mode, +software is responsible for byte swapping. + +USAGE: + +1. The host system that is running on MPC8240 + shall link the files listed here. The memory + location of driver routines shall take into + account of that driver routines need to run + in supervisor mode and they process external + interrupts. + + The routine epic_exception shall be called by + exception vector at location 0x500, i.e., + 603e core external exception vector. + +2. The host system is responsible for configuring + the MPC8240 including Embedded Utilities Memory + Block. All EPIC driver functions require the + content of Embedded Utilities Memory Block + Base Address Register, EUMBBAR, as the first + parameter. + +3. Before EPIC unit of MPC8240 can be used, + initialize EPIC unit by calling epicInit + with the corresponding parameters. + + The initialization shall disable the 603e + core External Exception by calling CoreExtIntDisable( ). + Next, call epicInit( ). Last, enable the 603e core + External Exception by calling CoreExtIntEnable( ). + +4. After EPIC unit has been successfully initialized, + epicIntSourceSet( ) shall be used to register each + external interrupt source. Anytime, an external + interrupt source can be disabled or enabled by + calling corresponding function, epicIntDisable( ), + or epicIntEnable( ). + + Global Timers' resource, base count and frequency, + can be changed by calling epicTmFrequencySet( ) + and epicTmBaseSet( ). + + To stop counting a specific global timer, use + the function, epicTmInhibit while epicTmEnable + can be used to start counting a timer. + +5. To mask a set of external interrupts that are + are certain level below, epicIntPrioritySet( ) + can be used. For example, if the processor's + current task priority register is set to 0x7, + only interrupts of priority 0x8 or higher will + be passed to the processor. + + Be careful when using this function. It may + corrupt the current interrupt pending, selector, + and request registers, resulting an invalid vetor. + + After enabling an interrupt, disable it may also + cause an invalid vector. User may consider using + the spurious vector interrupt service routine to + handle this case. + +6. The EPIC driver routines contains a set + of utilities, Set and Get, for host system + to query and modify the desired EPIC source + registers. + +7. Each external interrupt source shall register + its interrupt service routine. The routine + shall contain all interrupt source specific + processes and keep as short as possible. + + Special customized end of interrupt routine + is optional. If it is needed, it shall contain + the external interrupt source specific end of + interrupt process. + + External interrupt exception vector at 0x500 + shall always call the epicEOI just before + rfi instruction. Refer to the routine, + epic_exception, for a code sample. diff --git a/arch/powerpc/cpu/mpc824x/drivers/epic/epic.h b/arch/powerpc/cpu/mpc824x/drivers/epic/epic.h new file mode 100644 index 0000000..58f81c5 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/drivers/epic/epic.h @@ -0,0 +1,163 @@ +/********************************************************************* + * mpc8240epic.h - EPIC module of the MPC8240 micro-controller + * + * Copyrigh 1999 Motorola Inc. + * + * Modification History: + * ===================== + * 01a,04Feb99,My Created. + * 15Nov200, robt -modified to use in U-Boot + * +*/ + +#ifndef __INCEPICh +#define __INCEPICh + +#define ULONG unsigned long +#define MAXVEC 20 +#define MAXIRQ 5 /* IRQs */ +#define EPIC_DIRECT_IRQ 0 /* Direct interrupt type */ + +/* EPIC register addresses */ + +#define EPIC_EUMBBAR 0x40000 /* EUMBBAR of EPIC */ +#define EPIC_FEATURES_REG (EPIC_EUMBBAR + 0x01000)/* Feature reporting */ +#define EPIC_GLOBAL_REG (EPIC_EUMBBAR + 0x01020)/* Global config. */ +#define EPIC_INT_CONF_REG (EPIC_EUMBBAR + 0x01030)/* Interrupt config. */ +#define EPIC_VENDOR_ID_REG (EPIC_EUMBBAR + 0x01080)/* Vendor id */ +#define EPIC_PROC_INIT_REG (EPIC_EUMBBAR + 0x01090)/* Processor init. */ +#define EPIC_SPUR_VEC_REG (EPIC_EUMBBAR + 0x010e0)/* Spurious vector */ +#define EPIC_TM_FREQ_REG (EPIC_EUMBBAR + 0x010f0)/* Timer Frequency */ + +#define EPIC_TM0_CUR_COUNT_REG (EPIC_EUMBBAR + 0x01100)/* Gbl TM0 Cur. Count*/ +#define EPIC_TM0_BASE_COUNT_REG (EPIC_EUMBBAR + 0x01110)/* Gbl TM0 Base Count*/ +#define EPIC_TM0_VEC_REG (EPIC_EUMBBAR + 0x01120)/* Gbl TM0 Vector Pri*/ +#define EPIC_TM0_DES_REG (EPIC_EUMBBAR + 0x01130)/* Gbl TM0 Dest. */ + +#define EPIC_TM1_CUR_COUNT_REG (EPIC_EUMBBAR + 0x01140)/* Gbl TM1 Cur. Count*/ +#define EPIC_TM1_BASE_COUNT_REG (EPIC_EUMBBAR + 0x01150)/* Gbl TM1 Base Count*/ +#define EPIC_TM1_VEC_REG (EPIC_EUMBBAR + 0x01160)/* Gbl TM1 Vector Pri*/ +#define EPIC_TM1_DES_REG (EPIC_EUMBBAR + 0x01170)/* Gbl TM1 Dest. */ + +#define EPIC_TM2_CUR_COUNT_REG (EPIC_EUMBBAR + 0x01180)/* Gbl TM2 Cur. Count*/ +#define EPIC_TM2_BASE_COUNT_REG (EPIC_EUMBBAR + 0x01190)/* Gbl TM2 Base Count*/ +#define EPIC_TM2_VEC_REG (EPIC_EUMBBAR + 0x011a0)/* Gbl TM2 Vector Pri*/ +#define EPIC_TM2_DES_REG (EPIC_EUMBBAR + 0x011b0)/* Gbl TM2 Dest */ + +#define EPIC_TM3_CUR_COUNT_REG (EPIC_EUMBBAR + 0x011c0)/* Gbl TM3 Cur. Count*/ +#define EPIC_TM3_BASE_COUNT_REG (EPIC_EUMBBAR + 0x011d0)/* Gbl TM3 Base Count*/ +#define EPIC_TM3_VEC_REG (EPIC_EUMBBAR + 0x011e0)/* Gbl TM3 Vector Pri*/ +#define EPIC_TM3_DES_REG (EPIC_EUMBBAR + 0x011f0)/* Gbl TM3 Dest. */ + +#define EPIC_EX_INT0_VEC_REG (EPIC_EUMBBAR + 0x10200)/* Ext. Int. Sr0 Des */ +#define EPIC_EX_INT0_DES_REG (EPIC_EUMBBAR + 0x10210)/* Ext. Int. Sr0 Vect*/ +#define EPIC_EX_INT1_VEC_REG (EPIC_EUMBBAR + 0x10220)/* Ext. Int. Sr1 Des */ +#define EPIC_EX_INT1_DES_REG (EPIC_EUMBBAR + 0x10230)/* Ext. Int. Sr1 Vect*/ +#define EPIC_EX_INT2_VEC_REG (EPIC_EUMBBAR + 0x10240)/* Ext. Int. Sr2 Des */ +#define EPIC_EX_INT2_DES_REG (EPIC_EUMBBAR + 0x10250)/* Ext. Int. Sr2 Vect*/ +#define EPIC_EX_INT3_VEC_REG (EPIC_EUMBBAR + 0x10260)/* Ext. Int. Sr3 Des */ +#define EPIC_EX_INT3_DES_REG (EPIC_EUMBBAR + 0x10270)/* Ext. Int. Sr3 Vect*/ +#define EPIC_EX_INT4_VEC_REG (EPIC_EUMBBAR + 0x10280)/* Ext. Int. Sr4 Des */ +#define EPIC_EX_INT4_DES_REG (EPIC_EUMBBAR + 0x10290)/* Ext. Int. Sr4 Vect*/ + +#define EPIC_SR_INT0_VEC_REG (EPIC_EUMBBAR + 0x10200)/* Sr. Int. Sr0 Des */ +#define EPIC_SR_INT0_DES_REG (EPIC_EUMBBAR + 0x10210)/* Sr. Int. Sr0 Vect */ +#define EPIC_SR_INT1_VEC_REG (EPIC_EUMBBAR + 0x10220)/* Sr. Int. Sr1 Des */ +#define EPIC_SR_INT1_DES_REG (EPIC_EUMBBAR + 0x10230)/* Sr. Int. Sr1 Vect.*/ +#define EPIC_SR_INT2_VEC_REG (EPIC_EUMBBAR + 0x10240)/* Sr. Int. Sr2 Des */ +#define EPIC_SR_INT2_DES_REG (EPIC_EUMBBAR + 0x10250)/* Sr. Int. Sr2 Vect.*/ +#define EPIC_SR_INT3_VEC_REG (EPIC_EUMBBAR + 0x10260)/* Sr. Int. Sr3 Des */ +#define EPIC_SR_INT3_DES_REG (EPIC_EUMBBAR + 0x10270)/* Sr. Int. Sr3 Vect.*/ +#define EPIC_SR_INT4_VEC_REG (EPIC_EUMBBAR + 0x10280)/* Sr. Int. Sr4 Des */ +#define EPIC_SR_INT4_DES_REG (EPIC_EUMBBAR + 0x10290)/* Sr. Int. Sr4 Vect.*/ + +#define EPIC_SR_INT5_VEC_REG (EPIC_EUMBBAR + 0x102a0)/* Sr. Int. Sr5 Des */ +#define EPIC_SR_INT5_DES_REG (EPIC_EUMBBAR + 0x102b0)/* Sr. Int. Sr5 Vect.*/ +#define EPIC_SR_INT6_VEC_REG (EPIC_EUMBBAR + 0x102c0)/* Sr. Int. Sr6 Des */ +#define EPIC_SR_INT6_DES_REG (EPIC_EUMBBAR + 0x102d0)/* Sr. Int. Sr6 Vect.*/ +#define EPIC_SR_INT7_VEC_REG (EPIC_EUMBBAR + 0x102e0)/* Sr. Int. Sr7 Des */ +#define EPIC_SR_INT7_DES_REG (EPIC_EUMBBAR + 0x102f0)/* Sr. Int. Sr7 Vect.*/ +#define EPIC_SR_INT8_VEC_REG (EPIC_EUMBBAR + 0x10300)/* Sr. Int. Sr8 Des */ +#define EPIC_SR_INT8_DES_REG (EPIC_EUMBBAR + 0x10310)/* Sr. Int. Sr8 Vect.*/ +#define EPIC_SR_INT9_VEC_REG (EPIC_EUMBBAR + 0x10320)/* Sr. Int. Sr9 Des */ +#define EPIC_SR_INT9_DES_REG (EPIC_EUMBBAR + 0x10330)/* Sr. Int. Sr9 Vect.*/ + +#define EPIC_SR_INT10_VEC_REG (EPIC_EUMBBAR + 0x10340)/* Sr. Int. Sr10 Des */ +#define EPIC_SR_INT10_DES_REG (EPIC_EUMBBAR + 0x10350)/* Sr. Int. Sr10 Vect*/ +#define EPIC_SR_INT11_VEC_REG (EPIC_EUMBBAR + 0x10360)/* Sr. Int. Sr11 Des */ +#define EPIC_SR_INT11_DES_REG (EPIC_EUMBBAR + 0x10370)/* Sr. Int. Sr11 Vect*/ +#define EPIC_SR_INT12_VEC_REG (EPIC_EUMBBAR + 0x10380)/* Sr. Int. Sr12 Des */ +#define EPIC_SR_INT12_DES_REG (EPIC_EUMBBAR + 0x10390)/* Sr. Int. Sr12 Vect*/ +#define EPIC_SR_INT13_VEC_REG (EPIC_EUMBBAR + 0x103a0)/* Sr. Int. Sr13 Des */ +#define EPIC_SR_INT13_DES_REG (EPIC_EUMBBAR + 0x103b0)/* Sr. Int. Sr13 Vect*/ +#define EPIC_SR_INT14_VEC_REG (EPIC_EUMBBAR + 0x103c0)/* Sr. Int. Sr14 Des */ +#define EPIC_SR_INT14_DES_REG (EPIC_EUMBBAR + 0x103d0)/* Sr. Int. Sr14 Vect*/ +#define EPIC_SR_INT15_VEC_REG (EPIC_EUMBBAR + 0x103e0)/* Sr. Int. Sr15 Des */ +#define EPIC_SR_INT15_DES_REG (EPIC_EUMBBAR + 0x103f0)/* Sr. Int. Sr15 Vect*/ + +#define EPIC_I2C_INT_VEC_REG (EPIC_EUMBBAR + 0x11020)/* I2C Int. Vect Pri.*/ +#define EPIC_I2C_INT_DES_REG (EPIC_EUMBBAR + 0x11030)/* I2C Int. Dest */ +#define EPIC_DMA0_INT_VEC_REG (EPIC_EUMBBAR + 0x11040)/* DMA0 Int. Vect Pri*/ +#define EPIC_DMA0_INT_DES_REG (EPIC_EUMBBAR + 0x11050)/* DMA0 Int. Dest */ +#define EPIC_DMA1_INT_VEC_REG (EPIC_EUMBBAR + 0x11060)/* DMA1 Int. Vect Pri*/ +#define EPIC_DMA1_INT_DES_REG (EPIC_EUMBBAR + 0x11070)/* DMA1 Int. Dest */ +#define EPIC_MSG_INT_VEC_REG (EPIC_EUMBBAR + 0x110c0)/* Msg Int. Vect Pri*/ +#define EPIC_MSG_INT_DES_REG (EPIC_EUMBBAR + 0x110d0)/* Msg Int. Dest */ + +#define EPIC_PROC_CTASK_PRI_REG (EPIC_EUMBBAR + 0x20080)/* Proc. current task*/ +#define EPIC_PROC_INT_ACK_REG (EPIC_EUMBBAR + 0x200a0)/* Int. acknowledge */ +#define EPIC_PROC_EOI_REG (EPIC_EUMBBAR + 0x200b0)/* End of interrupt */ + +#define EPIC_VEC_PRI_MASK 0x80000000 /* Mask Interrupt bit in IVPR */ +#define EPIC_VEC_PRI_DFLT_PRI 8 /* Interrupt Priority in IVPR */ + +/* Error code */ + +#define OK 0 +#define ERROR -1 + +/* function prototypes */ + +void epicVendorId( unsigned int *step, + unsigned int *devId, + unsigned int *venId + ); +void epicFeatures( unsigned int *noIRQs, + unsigned int *noCPUs, + unsigned int *VerId ); +extern void epicInit( unsigned int IRQType, unsigned int clkRatio); +ULONG sysEUMBBARRead ( ULONG regNum ); +void sysEUMBBARWrite ( ULONG regNum, ULONG regVal); +extern void epicTmFrequencySet( unsigned int frq ); +extern unsigned int epicTmFrequencyGet(void); +extern unsigned int epicTmBaseSet( ULONG srcAddr, + unsigned int cnt, + unsigned int inhibit ); +extern unsigned int epicTmBaseGet ( ULONG srcAddr, unsigned int *val ); +extern unsigned int epicTmCountGet( ULONG srcAddr, unsigned int *val ); +extern unsigned int epicTmInhibit( unsigned int timer ); +extern unsigned int epicTmEnable( ULONG srcAdr ); +extern void CoreExtIntEnable(void); /* Enable 603e external interrupts */ +extern void CoreExtIntDisable(void); /* Disable 603e external interrupts */ +extern unsigned char epicIntTaskGet(void); +extern void epicIntTaskSet( unsigned char val ); +extern unsigned int epicIntAck(void); +extern void epicSprSet( unsigned int eumbbar, unsigned char ); +extern void epicConfigGet( unsigned int *clkRatio, + unsigned int *serEnable ); +extern void SrcVecTableInit(void); +extern unsigned int epicModeGet(void); +extern void epicIntEnable(int Vect); +extern void epicIntDisable(int Vect); +extern int epicIntSourceConfig(int Vect, int Polarity, int Sense, int Prio); +extern unsigned int epicIntAck(void); +extern void epicEOI(void); +extern int epicCurTaskPrioSet(int Vect); + +struct SrcVecTable + { + ULONG srcAddr; + char srcName[40]; + }; + +#endif /* EPIC_H */ diff --git a/arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c b/arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c new file mode 100644 index 0000000..ecbb42d --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c @@ -0,0 +1,517 @@ +/************************************************** + * + * copyright @ motorola, 1999 + * + *************************************************/ +#include <mpc824x.h> +#include <common.h> +#include "epic.h" + + +#define PRINT(format, args...) printf(format , ## args) + +typedef void (*VOIDFUNCPTR) (void); /* ptr to function returning void */ +struct SrcVecTable SrcVecTable[MAXVEC] = /* Addr/Vector cross-reference tbl */ + { + { EPIC_EX_INT0_VEC_REG, "External Direct/Serial Source 0"}, + { EPIC_EX_INT1_VEC_REG, "External Direct/Serial Source 1"}, + { EPIC_EX_INT2_VEC_REG, "External Direct/Serial Source 2"}, + { EPIC_EX_INT3_VEC_REG, "External Direct/Serial Source 3"}, + { EPIC_EX_INT4_VEC_REG, "External Direct/Serial Source 4"}, + + { EPIC_SR_INT5_VEC_REG, "External Serial Source 5"}, + { EPIC_SR_INT6_VEC_REG, "External Serial Source 6"}, + { EPIC_SR_INT7_VEC_REG, "External Serial Source 7"}, + { EPIC_SR_INT8_VEC_REG, "External Serial Source 8"}, + { EPIC_SR_INT9_VEC_REG, "External Serial Source 9"}, + { EPIC_SR_INT10_VEC_REG, "External Serial Source 10"}, + { EPIC_SR_INT11_VEC_REG, "External Serial Source 11"}, + { EPIC_SR_INT12_VEC_REG, "External Serial Source 12"}, + { EPIC_SR_INT13_VEC_REG, "External Serial Source 13"}, + { EPIC_SR_INT14_VEC_REG, "External Serial Source 14"}, + { EPIC_SR_INT15_VEC_REG, "External Serial Source 15"}, + + { EPIC_I2C_INT_VEC_REG, "Internal I2C Source"}, + { EPIC_DMA0_INT_VEC_REG, "Internal DMA0 Source"}, + { EPIC_DMA1_INT_VEC_REG, "Internal DMA1 Source"}, + { EPIC_MSG_INT_VEC_REG, "Internal Message Source"}, + }; + +VOIDFUNCPTR intVecTbl[MAXVEC]; /* Interrupt vector table */ + + +/**************************************************************************** +* epicInit - Initialize the EPIC registers +* +* This routine resets the Global Configuration Register, thus it: +* - Disables all interrupts +* - Sets epic registers to reset values +* - Sets the value of the Processor Current Task Priority to the +* highest priority (0xF). +* epicInit then sets the EPIC operation mode to Mixed Mode (vs. Pass +* Through or 8259 compatible mode). +* +* If IRQType (input) is Direct IRQs: +* - IRQType is written to the SIE bit of the EPIC Interrupt +* Configuration register (ICR). +* - clkRatio is ignored. +* If IRQType is Serial IRQs: +* - both IRQType and clkRatio will be written to the ICR register +*/ + +void epicInit + ( + unsigned int IRQType, /* Direct or Serial */ + unsigned int clkRatio /* Clk Ratio for Serial IRQs */ + ) + { + ULONG tmp; + + tmp = sysEUMBBARRead(EPIC_GLOBAL_REG); + tmp |= 0xa0000000; /* Set the Global Conf. register */ + sysEUMBBARWrite(EPIC_GLOBAL_REG, tmp); + /* + * Wait for EPIC to reset - CLH + */ + while( (sysEUMBBARRead(EPIC_GLOBAL_REG) & 0x80000000) == 1); + sysEUMBBARWrite(EPIC_GLOBAL_REG, 0x20000000); + tmp = sysEUMBBARRead(EPIC_INT_CONF_REG); /* Read interrupt conf. reg */ + + if (IRQType == EPIC_DIRECT_IRQ) /* direct mode */ + sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp & 0xf7ffffff); + else /* Serial mode */ + { + tmp = (clkRatio << 28) | 0x08000000; /* Set clock ratio */ + sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp); + } + + while (epicIntAck() != 0xff) /* Clear all pending interrupts */ + epicEOI(); +} + +/**************************************************************************** + * epicIntEnable - Enable an interrupt source + * + * This routine clears the mask bit of an external, an internal or + * a Timer register to enable the interrupt. + * + * RETURNS: None + */ +void epicIntEnable(int intVec) +{ + ULONG tmp; + ULONG srAddr; + + srAddr = SrcVecTable[intVec].srcAddr; /* Retrieve src Vec/Prio register */ + tmp = sysEUMBBARRead(srAddr); + tmp &= ~EPIC_VEC_PRI_MASK; /* Clear the mask bit */ + tmp |= (EPIC_VEC_PRI_DFLT_PRI << 16); /* Set priority to Default - CLH */ + tmp |= intVec; /* Set Vector number */ + sysEUMBBARWrite(srAddr, tmp); + + return; + } + +/**************************************************************************** + * epicIntDisable - Disable an interrupt source + * + * This routine sets the mask bit of an external, an internal or + * a Timer register to disable the interrupt. + * + * RETURNS: OK or ERROR + * + */ + +void epicIntDisable + ( + int intVec /* Interrupt vector number */ + ) + { + + ULONG tmp, srAddr; + + srAddr = SrcVecTable[intVec].srcAddr; + tmp = sysEUMBBARRead(srAddr); + tmp |= 0x80000000; /* Set the mask bit */ + sysEUMBBARWrite(srAddr, tmp); + return; + } + +/**************************************************************************** + * epicIntSourceConfig - Set properties of an interrupt source + * + * This function sets interrupt properites (Polarity, Sense, Interrupt + * Prority, and Interrupt Vector) of an Interrupt Source. The properties + * can be set when the current source is not in-request or in-service, + * which is determined by the Activity bit. This routine return ERROR + * if the the Activity bit is 1 (in-request or in-service). + * + * This function assumes that the Source Vector/Priority register (input) + * is a valid address. + * + * RETURNS: OK or ERROR + */ + +int epicIntSourceConfig + ( + int Vect, /* interrupt source vector number */ + int Polarity, /* interrupt source polarity */ + int Sense, /* interrupt source Sense */ + int Prio /* interrupt source priority */ + ) + + { + ULONG tmp, newVal; + ULONG actBit, srAddr; + + srAddr = SrcVecTable[Vect].srcAddr; + tmp = sysEUMBBARRead(srAddr); + actBit = (tmp & 40000000) >> 30; /* retrieve activity bit - bit 30 */ + if (actBit == 1) + return ERROR; + + tmp &= 0xff30ff00; /* Erase previously set P,S,Prio,Vector bits */ + newVal = (Polarity << 23) | (Sense << 22) | (Prio << 16) | Vect; + sysEUMBBARWrite(srAddr, tmp | newVal ); + return (OK); + } + +/**************************************************************************** + * epicIntAck - acknowledge an interrupt + * + * This function reads the Interrupt acknowldge register and return + * the vector number of the highest pending interrupt. + * + * RETURNS: Interrupt Vector number. + */ + +unsigned int epicIntAck(void) +{ + return(sysEUMBBARRead( EPIC_PROC_INT_ACK_REG )); +} + +/**************************************************************************** + * epicEOI - signal an end of interrupt + * + * This function writes 0x0 to the EOI register to signal end of interrupt. + * It is usually called after an interrupt routine is served. + * + * RETURNS: None + */ + +void epicEOI(void) + { + sysEUMBBARWrite(EPIC_PROC_EOI_REG, 0x0); + } + +/**************************************************************************** + * epicCurTaskPrioSet - sets the priority of the Processor Current Task + * + * This function should be called after epicInit() to lower the priority + * of the processor current task. + * + * RETURNS: OK or ERROR + */ + +int epicCurTaskPrioSet + ( + int prioNum /* New priority value */ + ) + { + + if ( (prioNum < 0) || (prioNum > 0xF)) + return ERROR; + sysEUMBBARWrite(EPIC_PROC_CTASK_PRI_REG, prioNum); + return OK; + } + + +/************************************************************************ + * function: epicIntTaskGet + * + * description: Get value of processor current interrupt task priority register + * + * note: + ***********************************************************************/ +unsigned char epicIntTaskGet() +{ + /* get the interrupt task priority register */ + ULONG reg; + unsigned char rec; + + reg = sysEUMBBARRead( EPIC_PROC_CTASK_PRI_REG ); + rec = ( reg & 0x0F ); + return rec; +} + + +/************************************************************** + * function: epicISR + * + * description: EPIC service routine called by the core exception + * at 0x500 + * + * note: + **************************************************************/ +unsigned int epicISR(void) +{ + return 0; +} + + +/************************************************************ + * function: epicModeGet + * + * description: query EPIC mode, return 0 if pass through mode + * return 1 if mixed mode + * + * note: + *************************************************************/ +unsigned int epicModeGet(void) +{ + ULONG val; + + val = sysEUMBBARRead( EPIC_GLOBAL_REG ); + return (( val & 0x20000000 ) >> 29); +} + + +/********************************************* + * function: epicConfigGet + * + * description: Get the EPIC interrupt Configuration + * return 0 if not error, otherwise return 1 + * + * note: + ********************************************/ +void epicConfigGet( unsigned int *clkRatio, unsigned int *serEnable) +{ + ULONG val; + + val = sysEUMBBARRead( EPIC_INT_CONF_REG ); + *clkRatio = ( val & 0x70000000 ) >> 28; + *serEnable = ( val & 0x8000000 ) >> 27; +} + + +/******************************************************************* + * sysEUMBBARRead - Read a 32-bit EUMBBAR register + * + * This routine reads the content of a register in the Embedded + * Utilities Memory Block, and swaps to big endian before returning + * the value. + * + * RETURNS: The content of the specified EUMBBAR register. + */ + +ULONG sysEUMBBARRead + ( + ULONG regNum + ) + { + ULONG temp; + + temp = *(ULONG *) (CONFIG_SYS_EUMB_ADDR + regNum); + return ( LONGSWAP(temp)); + } + +/******************************************************************* + * sysEUMBBARWrite - Write a 32-bit EUMBBAR register + * + * This routine swaps the value to little endian then writes it to + * a register in the Embedded Utilities Memory Block address space. + * + * RETURNS: N/A + */ + +void sysEUMBBARWrite + ( + ULONG regNum, /* EUMBBAR register address */ + ULONG regVal /* Value to be written */ + ) + { + + *(ULONG *) (CONFIG_SYS_EUMB_ADDR + regNum) = LONGSWAP(regVal); + return ; + } + + +/******************************************************** + * function: epicVendorId + * + * description: return the EPIC Vendor Identification + * register: + * + * siliccon version, device id, and vendor id + * + * note: + ********************************************************/ +void epicVendorId + ( + unsigned int *step, + unsigned int *devId, + unsigned int *venId + ) + { + ULONG val; + val = sysEUMBBARRead( EPIC_VENDOR_ID_REG ); + *step = ( val & 0x00FF0000 ) >> 16; + *devId = ( val & 0x0000FF00 ) >> 8; + *venId = ( val & 0x000000FF ); + } + +/************************************************** + * function: epicFeatures + * + * description: return the number of IRQ supported, + * number of CPU, and the version of the + * OpenEPIC + * + * note: + *************************************************/ +void epicFeatures + ( + unsigned int *noIRQs, + unsigned int *noCPUs, + unsigned int *verId + ) + { + ULONG val; + + val = sysEUMBBARRead( EPIC_FEATURES_REG ); + *noIRQs = ( val & 0x07FF0000 ) >> 16; + *noCPUs = ( val & 0x00001F00 ) >> 8; + *verId = ( val & 0x000000FF ); +} + + +/********************************************************* + * function: epciTmFrequncySet + * + * description: Set the timer frequency reporting register + ********************************************************/ +void epicTmFrequencySet( unsigned int frq ) +{ + sysEUMBBARWrite(EPIC_TM_FREQ_REG, frq); +} + +/******************************************************* + * function: epicTmFrequncyGet + * + * description: Get the current value of the Timer Frequency + * Reporting register + * + ******************************************************/ +unsigned int epicTmFrequencyGet(void) +{ + return( sysEUMBBARRead(EPIC_TM_FREQ_REG)) ; +} + + +/**************************************************** + * function: epicTmBaseSet + * + * description: Set the #n global timer base count register + * return 0 if no error, otherwise return 1. + * + * note: + ****************************************************/ +unsigned int epicTmBaseSet + ( + ULONG srcAddr, /* Address of the Timer Base register */ + unsigned int cnt, /* Base count */ + unsigned int inhibit /* 1 - count inhibit */ + ) +{ + + unsigned int val = 0x80000000; + /* First inhibit counting the timer */ + sysEUMBBARWrite(srcAddr, val) ; + + /* set the new value */ + val = (cnt & 0x7fffffff) | ((inhibit & 0x1) << 31); + sysEUMBBARWrite(srcAddr, val) ; + return 0; +} + +/*********************************************************************** + * function: epicTmBaseGet + * + * description: Get the current value of the global timer base count register + * return 0 if no error, otherwise return 1. + * + * note: + ***********************************************************************/ +unsigned int epicTmBaseGet( ULONG srcAddr, unsigned int *val ) +{ + *val = sysEUMBBARRead( srcAddr ); + *val = *val & 0x7fffffff; + return 0; +} + +/*********************************************************** + * function: epicTmCountGet + * + * description: Get the value of a given global timer + * current count register + * return 0 if no error, otherwise return 1 + * note: + **********************************************************/ +unsigned int epicTmCountGet( ULONG srcAddr, unsigned int *val ) +{ + *val = sysEUMBBARRead( srcAddr ); + *val = *val & 0x7fffffff; + return 0; +} + + +/*********************************************************** + * function: epicTmInhibit + * + * description: Stop counting of a given global timer + * return 0 if no error, otherwise return 1 + * + * note: + ***********************************************************/ +unsigned int epicTmInhibit( unsigned int srcAddr ) +{ + ULONG val; + + val = sysEUMBBARRead( srcAddr ); + val |= 0x80000000; + sysEUMBBARWrite( srcAddr, val ); + return 0; +} + +/****************************************************************** + * function: epicTmEnable + * + * description: Enable counting of a given global timer + * return 0 if no error, otherwise return 1 + * + * note: + *****************************************************************/ +unsigned int epicTmEnable( ULONG srcAddr ) +{ + ULONG val; + + val = sysEUMBBARRead( srcAddr ); + val &= 0x7fffffff; + sysEUMBBARWrite( srcAddr, val ); + return 0; +} + +void epicSourcePrint(int Vect) + { + ULONG srcVal; + + srcVal = sysEUMBBARRead(SrcVecTable[Vect].srcAddr); + PRINT("%s\n", SrcVecTable[Vect].srcName); + PRINT("Address = 0x%lx\n", SrcVecTable[Vect].srcAddr); + PRINT("Vector = %ld\n", (srcVal & 0x000000FF) ); + PRINT("Mask = %ld\n", srcVal >> 31); + PRINT("Activitiy = %ld\n", (srcVal & 40000000) >> 30); + PRINT("Polarity = %ld\n", (srcVal & 0x00800000) >> 23); + PRINT("Sense = %ld\n", (srcVal & 0x00400000) >> 22); + PRINT("Priority = %ld\n", (srcVal & 0x000F0000) >> 16); + } diff --git a/arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S b/arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S new file mode 100644 index 0000000..52d19aa --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S @@ -0,0 +1,196 @@ +/************************************** + * + * copyright @ Motorola, 1999 + * + **************************************/ + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> +#include <asm/processor.h> + +/********************************************* + * function: CoreExtIntEnable + * + * description: Enable 603e core external interrupt + * + * note: mtmsr is context-synchronization + **********************************************/ + .text + .align 2 + .global CoreExtIntEnable +CoreExtIntEnable: + mfmsr r3 + + ori r3,r3,0x8000 /* enable external interrupt */ + mtmsr r3 + + bclr 20, 0 + +/******************************************* + * function: CoreExtIntDisable + * + * description: Disable 603e core external interrupt + * + * note: + *******************************************/ + .text + .align 2 + .global CoreExtIntDisable +CoreExtIntDisable: + mfmsr r4 + + xor r3,r3,r3 + or r3,r3,r4 + + andis. r4,r4,0xffff + andi. r3,r3,0x7fff /* disable external interrupt */ + + or r3,r3,r4 + mtmsr r3 + + bclr 20, 0 + +/********************************************************* + * function: epicEOI + * + * description: signal the EOI and restore machine status + * Input: r3 - value of eumbbar + * Output: r3 - value of eumbbar + * r4 - ISR vector value + * note: + ********************************************************/ + .text + .align 2 + .global epicEOI +epicEOI: + lis r5,0x0006 /* Build End Of Interrupt Register offset */ + ori r5,r5,0x00b0 + xor r7,r7,r7 /* Clear r7 */ + stwbrx r7,r5,r3 /* Save r7, writing to this register will + * intidate the end of processing the + * highest interrupt. + */ + sync + + /* ---RESTORE MACHINE STATE */ + mfmsr r13 /* Clear Recoverable Interrupt bit in MSR */ + or r7,r7,r13 + + andis. r7,r7,0xffff + andi. r13,r13,0x7ffd /* (and disable interrupts) */ + or r13,r13,r7 + mtmsr r13 + + lwz r13,0x1c(r1) /* pull ctr */ + mtctr r13 + + lwz r13,0x18(r1) /* pull xer */ + mtctr r13 + + lwz r13,0x14(r1) /* pull lr */ + mtctr r13 + + lwz r13,0x10(r1) /* Pull SRR1 from stack */ + mtspr SRR1,r13 /* Restore SRR1 */ + + lwz r13,0xc(r1) /* Pull SRR0 from stack */ + mtspr SRR0,r13 /* Restore SRR0 */ + + lwz r13,0x8(r1) /* Pull User stack pointer from stack */ + mtspr SPRG1,r13 /* Restore SPRG1 */ + + lwz r4,0x4(r1) /* vector value */ + lwz r3,0x0(r1) /* eumbbar */ + sync + + addi r1,r1,0x20 /* Deallocate stack */ + mtspr SPRG0,r1 /* Save updated Supervisor stack pointer */ + mfspr r1,SPRG1 /* Restore User stack pointer */ + + bclr 20,0 + +/*********************************************************** + * function: exception routine called by exception vector + * at 0x500, external interrupt + * + * description: Kahlua EPIC controller + * + * input: r3 - content of eumbbar + * output: r3 - ISR return value + * r4 - Interrupt vector number + * note: + ***********************************************************/ + + .text + .align 2 + .global epic_exception + +epic_exception: + + /*---SAVE MACHINE STATE TO A STACK */ + mtspr SPRG1,r1 /* Save User stack pointer to SPRG1 */ + mfspr r1,SPRG0 /* Load Supervisor stack pointer into r1 */ + + stwu r3,-0x20(r1) /* Push the value of eumbbar onto stack */ + + mfspr r3,SPRG1 /* Push User stack pointer onto stack */ + stw r3,0x8(r1) + mfspr r3,SRR0 /* Push SRR0 onto stack */ + stw r1,0xc(r1) + mfspr r3,SRR1 /* Push SRR1 onto stack */ + stw r3,0x10(r1) + mflr r3 + stw r3,0x14(r1) /* Push LR */ + mfxer r3 + stw r3,0x18(r1) /* Push Xer */ + mfctr r3 + stw r3,0x1c(r1) /* Push CTR */ + + mtspr SPRG0,r1 /* Save updated Supervisor stack pointer + * value to SPRG0 + */ + mfmsr r3 + ori r3,r3,0x0002 /* Set Recoverable Interrupt bit in MSR */ + mtmsr r3 + + /* ---READ IN THE EUMBAR REGISTER */ + lwz r6,0(r1) /* this is eumbbar */ + sync + + /* ---READ EPIC REGISTER: PROCESSOR INTERRUPT ACKNOWLEDGE REGISTER */ + lis r5,0x0006 /* Build Interrupt Acknowledge Register + * offset + */ + ori r5,r5,0x00a0 + lwbrx r7,r5,r6 /* Load interrupt vector into r7 */ + sync + + /* --MASK OFF ALL BITS EXCEPT THE VECTOR */ + xor r3,r3,r3 + xor r4,r4,r4 + or r3, r3, r6 /* eumbbar in r3 */ + andi. r4,r7,0x00ff /* Mask off bits, vector in r4 */ + + stw r4,0x04(r1) /* save the vector value */ + + lis r5,epicISR@ha + ori r5,r5,epicISR@l + mtlr r5 + blrl + + xor r30,r30,r30 + or r30,r30,r3 /* save the r3 which containts the return value from epicISR */ + + /* ---READ IN THE EUMBAR REGISTER */ + lwz r3,0(r1) + sync + + lis r5,epicEOI@ha + ori r5,r5,epicEOI@l + mtlr r5 + blrl + + xor r3,r3,r3 + or r3,r3,r30 /* restore the ISR return value */ + + bclr 20,0 diff --git a/arch/powerpc/cpu/mpc824x/drivers/epic/epicutil.S b/arch/powerpc/cpu/mpc824x/drivers/epic/epicutil.S new file mode 100644 index 0000000..4877050 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/drivers/epic/epicutil.S @@ -0,0 +1,57 @@ +/************************************** + * + * copyright @ Motorola, 1999 + * + * + * This file contains two commonly used + * lower level utility routines. + * + * The utility routines are also in other + * Kahlua device driver libraries. The + * need to be linked in only once. + **************************************/ + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +/********************************************************** + * function: load_runtime_reg + * + * input: r3 - value of eumbbar + * r4 - register offset in embedded utility space + * + * output: r3 - register content + **********************************************************/ + .text + .align 2 + .global load_runtime_reg + +load_runtime_reg: + + xor r5,r5,r5 + or r5,r5,r3 /* save eumbbar */ + + lwbrx r3,r4,r5 + sync + + bclr 20, 0 + +/**************************************************************** + * function: store_runtime_reg + * + * input: r3 - value of eumbbar + * r4 - register offset in embedded utility space + * r5 - new value to be stored + * + ****************************************************************/ + .text + .align 2 + .global store_runtime_reg +store_runtime_reg: + + xor r0,r0,r0 + + stwbrx r5, r4, r3 + sync + + bclr 20,0 diff --git a/arch/powerpc/cpu/mpc824x/drivers/errors.h b/arch/powerpc/cpu/mpc824x/drivers/errors.h new file mode 100644 index 0000000..20794a2 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/drivers/errors.h @@ -0,0 +1,212 @@ +/* Copyright Motorola, Inc. 1993, 1994 + ALL RIGHTS RESERVED + + You are hereby granted a copyright license to use, modify, and + distribute the SOFTWARE so long as this entire notice is retained + without alteration in any modified and/or redistributed versions, + and that such modified versions are clearly identified as such. + No licenses are granted by implication, estoppel or otherwise under + any patents or trademarks of Motorola, Inc. + + The SOFTWARE is provided on an "AS IS" basis and without warranty. + To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS + ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR + PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH + REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS + THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS. + + To the maximum extent permitted by applicable law, IN NO EVENT SHALL + MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER + (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF + BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS + INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR + INABILITY TO USE THE SOFTWARE. Motorola assumes no responsibility + for the maintenance and support of the SOFTWARE. + +*/ + + +#include "config.h" + +/* + 1 2 3 4 5 6 7 8 +01234567890123456789012345678901234567890123456789012345678901234567890123456789 +*/ +/* List define statements here */ + +/* These are for all the toolboxes and functions to use. These will help +to standardize the error handling in the current project */ + + /* this is the "data type" for the error + messages in the system */ +#define STATUS unsigned int + + /* this is a success status code */ +#define SUCCESS 1 + + /* likewise this is failure */ +#define FAILURE 0 + +#define NUM_ERRORS 47 + +/* This first section of "defines" are for error codes ONLY. The called + routine will return one of these error codes to the caller. If the final + returned code is "VALID", then everything is a-okay. However, if one + of the functions returns a non-valid status, that error code should be + propogated back to all the callers. At the end, the last caller will + call an error_processing function, and send in the status which was + returned. It's up to the error_processing function to determine which + error occured (as indicated by the status), and print an appropriate + message back to the user. +*/ +/*----------------------------------------------------------------------*/ +/* these are specifically for the parser routines */ + +#define UNKNOWN_COMMAND 0xfb00 /* "unrecognized command " */ +#define UNKNOWN_REGISTER 0xfb01 /* "unknown register "*/ +#define ILLEGAL_RD_STAGE 0xfb02 /* cannot specify reg. family in range*/ +#define ILLEGAL_REG_FAMILY 0xfb03 /* "cannot specify a range of special + or miscellaneous registers"*/ +#define RANGE_CROSS_FAMILY 0xfb04 /* "cannot specify a range across + register families" */ +#define UNIMPLEMENTED_STAGE 0xfb05 /* invalid rd or rmm parameter format */ +#define REG_NOT_WRITEABLE 0xfb06 /* "unknown operator in arguements"*/ +#define INVALID_FILENAME 0xfb07 /* "invalid download filename" */ +#define INVALID_BAUD_RATE 0xfb08 /* invalid baud rate from sb command */ +#define UNSUPPORTED_REGISTER 0xfb09 /* Special register is not supported */ +#define FOR_BOARD_ONLY 0xfb0a /* "Not available for Unix." */ + + +/*----------------------------------------------------------------------*/ +/* these are for the error checking toolbox */ + +#define INVALID 0xfd00 /* NOT valid */ +#define VALID 0xfd01 /* valid */ + + /* This error is found in the fcn: + is_right_size_input() to indicate + that the input was not 8 characters + long. */ +#define INVALID_SIZE 0xfd02 + + /* This error is found in the fcn: + is_valid_address_range() to indicate + that the address given falls outside + of valid memory defined by MEM_START + to MEM_END. + */ +#define OUT_OF_BOUNDS_ADDRESS 0xfd03 + + /* This error is found in the fcn: + is_valid_hex_input() to indicate that + one of more of the characters entered + are not valid hex characters. Valid + hex characters are 0-9, A-F, a-f. + */ +#define INVALID_HEX_INPUT 0xfd04 + + /* This error is found in the fcn: + is_valid_register_number() to indicate + that a given register does not exist. + */ +#define REG_NOT_READABLE 0xfd05 + + /* This error is found in the fcn: + is_word_aligned_address() to indicate + that the given address is not word- + aligned. A word-aligned address ends + in 0x0,0x4,0x8,0xc. + */ +#define NOT_WORD_ALIGNED 0xfd07 + + /* This error is found in the fcn: + is_valid_address_range() to indicate + that the starting address is greater + than the ending address. + */ +#define REVERSED_ADDRESS 0xfd08 + + /* this error tells us that the address + specified as the destination is within + the source addresses */ +#define RANGE_OVERLAP 0xfd09 + + +#define ERROR 0xfd0a /* An error occured */ +#define INVALID_PARAM 0xfd0b /* "invalid input parameter " */ + + +#define INVALID_FLAG 0xfd0c /* invalid flag */ + +/*----------------------------------------------------------------------*/ +/* these are for the getarg toolbox */ + +#define INVALID_NUMBER_ARGS 0xFE00 /* invalid number of commd arguements */ +#define UNKNOWN_PARAMETER 0xFE01 /* "unknown type of parameter "*/ + + +/*----------------------------------------------------------------------*/ +/* these are for the tokenizer toolbox */ + +#define ILLEGAL_CHARACTER 0xFF00 /* unrecognized char. in input stream*/ +#define TTL_NOT_SORTED 0xFF01 /* token translation list not sorted */ +#define TTL_NOT_DEFINED 0xFF02 /* token translation list not assigned*/ +#define INVALID_STRING 0xFF03 /* unable to extract string from input */ +#define BUFFER_EMPTY 0xFF04 /* "input buffer is empty" */ +#define INVALID_MODE 0xFF05 /* input buf is in an unrecognized mode*/ +#define TOK_INTERNAL_ERROR 0xFF06 /* "internal tokenizer error" */ +#define TOO_MANY_IBS 0xFF07 /* "too many open input buffers" */ +#define NO_OPEN_IBS 0xFF08 /* "no open input buffers" */ + + +/* these are for the read from screen toolbox */ + +#define RESERVED_WORD 0xFC00 /* used a reserved word as an arguement*/ + + +/* these are for the breakpoint routines */ + +#define FULL_BPDS 0xFA00 /* breakpoint data structure is full */ + + +/* THESE are for the downloader */ + +#define NOT_IN_S_RECORD_FORMAT 0xf900 /* "not in S-Record Format" */ +#define UNREC_RECORD_TYPE 0xf901 /* "unrecognized record type" */ +#define CONVERSION_ERROR 0xf902 /* "ascii to int conversion error" */ +#define INVALID_MEMORY 0xf903 /* "bad s-record memory address " */ + + +/* these are for the compression and decompression stuff */ + +#define COMP_UNK_CHARACTER 0xf800 /* "unknown compressed character " */ + +#define COMP_UNKNOWN_STATE 0xf801 /* "unknown binary state" */ + +#define NOT_IN_COMPRESSED_FORMAT 0xf802 /* not in compressed S-Record format */ + + +/* these are for the DUART handling things */ + + /* "unrecognized serial port configuration" */ +#define UNKNOWN_PORT_STATE 0xf700 + + +/* these are for the register toolbox */ + + /* "cannot find register in special + purpose register file " */ +#define SPR_NOT_FOUND 0xf600 + + +/* these are for the duart specific stuff */ + + /* "transparent mode needs access to + two serial ports" */ +#define TM_NEEDS_BOTH_PORTS 0xf500 + + +/*----------------------------------------------------------------------*/ +/* these are specifically for the flash routines */ +#define FLASH_ERROR 0xf100 /* general flash error */ diff --git a/arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c b/arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c new file mode 100644 index 0000000..637ae4c --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c @@ -0,0 +1,270 @@ +/* + * (C) Copyright 2003 + * Gleb Natapov <gnatapov@mrv.com> + * Some bits are taken from linux driver writen by adrian@humboldt.co.uk + * + * Hardware I2C driver for MPC107 PCI bridge. + * + * 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> + +#undef I2CDBG + +#ifdef CONFIG_HARD_I2C +#include <i2c.h> + +#define TIMEOUT (CONFIG_SYS_HZ/4) + +#define I2C_Addr ((unsigned *)(CONFIG_SYS_EUMB_ADDR + 0x3000)) + +#define I2CADR &I2C_Addr[0] +#define I2CFDR &I2C_Addr[1] +#define I2CCCR &I2C_Addr[2] +#define I2CCSR &I2C_Addr[3] +#define I2CCDR &I2C_Addr[4] + +#define MPC107_CCR_MEN 0x80 +#define MPC107_CCR_MIEN 0x40 +#define MPC107_CCR_MSTA 0x20 +#define MPC107_CCR_MTX 0x10 +#define MPC107_CCR_TXAK 0x08 +#define MPC107_CCR_RSTA 0x04 + +#define MPC107_CSR_MCF 0x80 +#define MPC107_CSR_MAAS 0x40 +#define MPC107_CSR_MBB 0x20 +#define MPC107_CSR_MAL 0x10 +#define MPC107_CSR_SRW 0x04 +#define MPC107_CSR_MIF 0x02 +#define MPC107_CSR_RXAK 0x01 + +#define I2C_READ 1 +#define I2C_WRITE 0 + +/* taken from linux include/asm-ppc/io.h */ +inline unsigned in_le32 (volatile unsigned *addr) +{ + unsigned ret; + + __asm__ __volatile__ ("lwbrx %0,0,%1;\n" + "twi 0,%0,0;\n" + "isync":"=r" (ret): "r" (addr), "m" (*addr)); + return ret; +} + +inline void out_le32 (volatile unsigned *addr, int val) +{ + __asm__ __volatile__ ("stwbrx %1,0,%2; eieio":"=m" (*addr):"r" (val), + "r" (addr)); +} + +#define writel(val, addr) out_le32(addr, val) +#define readl(addr) in_le32(addr) + +void i2c_init (int speed, int slaveadd) +{ + /* stop I2C controller */ + writel (0x0, I2CCCR); + /* set clock */ + writel (0x1020, I2CFDR); + /* write slave address */ + writel (slaveadd, I2CADR); + /* clear status register */ + writel (0x0, I2CCSR); + /* start I2C controller */ + writel (MPC107_CCR_MEN, I2CCCR); + + return; +} + +static __inline__ int i2c_wait4bus (void) +{ + ulong timeval = get_timer (0); + + while (readl (I2CCSR) & MPC107_CSR_MBB) + if (get_timer (timeval) > TIMEOUT) + return -1; + + return 0; +} + +static __inline__ int i2c_wait (int write) +{ + u32 csr; + ulong timeval = get_timer (0); + + do { + csr = readl (I2CCSR); + + if (!(csr & MPC107_CSR_MIF)) + continue; + + writel (0x0, I2CCSR); + + if (csr & MPC107_CSR_MAL) { +#ifdef I2CDBG + printf ("i2c_wait: MAL\n"); +#endif + return -1; + } + + if (!(csr & MPC107_CSR_MCF)) { +#ifdef I2CDBG + printf ("i2c_wait: unfinished\n"); +#endif + return -1; + } + + if (write == I2C_WRITE && (csr & MPC107_CSR_RXAK)) { +#ifdef I2CDBG + printf ("i2c_wait: No RXACK\n"); +#endif + return -1; + } + + return 0; + } while (get_timer (timeval) < TIMEOUT); + +#ifdef I2CDBG + printf ("i2c_wait: timed out\n"); +#endif + return -1; +} + +static __inline__ int i2c_write_addr (u8 dev, u8 dir, int rsta) +{ + writel (MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_MTX | + (rsta ? MPC107_CCR_RSTA : 0), I2CCCR); + + writel ((dev << 1) | dir, I2CCDR); + + if (i2c_wait (I2C_WRITE) < 0) + return 0; + + return 1; +} + +static __inline__ int __i2c_write (u8 * data, int length) +{ + int i; + + writel (MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_MTX, I2CCCR); + + for (i = 0; i < length; i++) { + writel (data[i], I2CCDR); + + if (i2c_wait (I2C_WRITE) < 0) + break; + } + + return i; +} + +static __inline__ int __i2c_read (u8 * data, int length) +{ + int i; + + writel (MPC107_CCR_MEN | MPC107_CCR_MSTA | + ((length == 1) ? MPC107_CCR_TXAK : 0), I2CCCR); + + /* dummy read */ + readl (I2CCDR); + + for (i = 0; i < length; i++) { + if (i2c_wait (I2C_READ) < 0) + break; + + /* Generate ack on last next to last byte */ + if (i == length - 2) + writel (MPC107_CCR_MEN | MPC107_CCR_MSTA | + MPC107_CCR_TXAK, I2CCCR); + + /* Generate stop on last byte */ + if (i == length - 1) + writel (MPC107_CCR_MEN | MPC107_CCR_TXAK, I2CCCR); + + data[i] = readl (I2CCDR); + } + + return i; +} + +int i2c_read (u8 dev, uint addr, int alen, u8 * data, int length) +{ + int i = 0; + u8 *a = (u8 *) & addr; + + if (i2c_wait4bus () < 0) + goto exit; + + if (i2c_write_addr (dev, I2C_WRITE, 0) == 0) + goto exit; + + if (__i2c_write (&a[4 - alen], alen) != alen) + goto exit; + + if (i2c_write_addr (dev, I2C_READ, 1) == 0) + goto exit; + + i = __i2c_read (data, length); + +exit: + writel (MPC107_CCR_MEN, I2CCCR); + + return !(i == length); +} + +int i2c_write (u8 dev, uint addr, int alen, u8 * data, int length) +{ + int i = 0; + u8 *a = (u8 *) & addr; + + if (i2c_wait4bus () < 0) + goto exit; + + if (i2c_write_addr (dev, I2C_WRITE, 0) == 0) + goto exit; + + if (__i2c_write (&a[4 - alen], alen) != alen) + goto exit; + + i = __i2c_write (data, length); + +exit: + writel (MPC107_CCR_MEN, I2CCCR); + + return !(i == length); +} + +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, (uchar *) &tmp, 1); +} + +#endif /* CONFIG_HARD_I2C */ diff --git a/arch/powerpc/cpu/mpc824x/drivers/i2c_export.h b/arch/powerpc/cpu/mpc824x/drivers/i2c_export.h new file mode 100644 index 0000000..6264d18 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/drivers/i2c_export.h @@ -0,0 +1,103 @@ +#ifndef I2C_EXPORT_H +#define I2C_EXPORT_H + +/**************************************************** + * + * Copyright Motrola 1999 + * + ****************************************************/ + +/* These are the defined return values for the I2C_do_transaction function. + * Any non-zero value indicates failure. Failure modes can be added for + * more detailed error reporting. + */ +typedef enum _i2c_status +{ + I2C_SUCCESS = 0, + I2C_ERROR, +} I2C_Status; + +/* These are the defined tasks for I2C_do_transaction. + * Modes for SLAVE_RCV and SLAVE_XMIT will be added. + */ +typedef enum _i2c_transaction_mode +{ + I2C_MASTER_RCV = 0, + I2C_MASTER_XMIT = 1, +} I2C_TRANSACTION_MODE; + +typedef enum _i2c_interrupt_mode +{ + I2C_INT_DISABLE = 0, + I2C_INT_ENABLE = 1, +} I2C_INTERRUPT_MODE; + +typedef enum _i2c_stop +{ + I2C_NO_STOP = 0, + I2C_STOP = 1, +} I2C_STOP_MODE; + +typedef enum _i2c_restart +{ + I2C_NO_RESTART = 0, + I2C_RESTART = 1, +} I2C_RESTART_MODE; + +/******************** App. API ******************** + * The application API is for user level application + * to use the functionality provided by I2C driver. + * This is a "generic" I2C interface, it should contain + * nothing specific to the Kahlua implementation. + * Only the generic functions are exported by the library. + * + * Note: Its App.s responsibility to swap the data + * byte. In our API, we just transfer whatever + * we are given + **************************************************/ + + +/* 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. + */ +extern I2C_Status I2C_Initialize( + unsigned char addr, /* driver's I2C slave address */ + I2C_INTERRUPT_MODE en_int, /* 1 - enable I2C interrupt + * 0 - disable I2C interrupt + */ + int (*app_print_function)(char *,...)); /* pointer to optional "printf" + * provided by application + */ + +/* 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 + * 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 + */ +extern 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); +#endif diff --git a/arch/powerpc/cpu/mpc824x/interrupts.c b/arch/powerpc/cpu/mpc824x/interrupts.c new file mode 100644 index 0000000..139c52c --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/interrupts.c @@ -0,0 +1,93 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * 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 <mpc824x.h> +#include <asm/processor.h> +#include <asm/pci_io.h> +#include <commproc.h> +#include "drivers/epic.h" + +int interrupt_init_cpu (unsigned *decrementer_count) +{ + *decrementer_count = (get_bus_freq (0) / 4) / CONFIG_SYS_HZ; + + /* + * It's all broken at the moment and I currently don't need + * interrupts. If you want to fix it, have a look at the epic + * drivers in dink32 v12. They do everthing and Motorola said + * I could use the dink source in this project as long as + * copyright notices remain intact. + */ + + epicInit (EPIC_DIRECT_IRQ, 0); + /* EPIC won't generate INT unless Current Task Pri < 15 */ + epicCurTaskPrioSet(0); + + return (0); +} + +/****************************************************************************/ + +/* + * Handle external interrupts + */ +void external_interrupt (struct pt_regs *regs) +{ + register unsigned long temp; + + pci_readl (CONFIG_SYS_EUMB_ADDR + EPIC_PROC_INT_ACK_REG, temp); + sync (); /* i'm not convinced this is needed, but dink source has it */ + temp &= 0xff; /*get vector */ + + /*TODO: handle them -... */ + epicEOI (); +} + +/****************************************************************************/ + +/* + * blank int handlers. + */ + +void +irq_install_handler (int vec, interrupt_handler_t * handler, void *arg) +{ +} + +void irq_free_handler (int vec) +{ + +} + +/*TODO: some handlers for winbond and 87308 interrupts + and what about generic pci inteerupts? + vga? + */ + +void timer_interrupt_cpu (struct pt_regs *regs) +{ + /* nothing to do here */ + return; +} diff --git a/arch/powerpc/cpu/mpc824x/pci.c b/arch/powerpc/cpu/mpc824x/pci.c new file mode 100644 index 0000000..72aaec7 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/pci.c @@ -0,0 +1,78 @@ +/* + * arch/powerpc/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_SYS_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/arch/powerpc/cpu/mpc824x/speed.c b/arch/powerpc/cpu/mpc824x/speed.c new file mode 100644 index 0000000..fdcb972 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/speed.c @@ -0,0 +1,118 @@ +/* + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2002 + * Gregory E. Allen, gallen@arlut.utexas.edu + * Applied Research Laboratories, The University of Texas at Austin + * + * 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 <mpc824x.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* ------------------------------------------------------------------------- */ +/* NOTE: This describes the proper use of this file. + * + * CONFIG_SYS_CLK_FREQ should be defined as the input frequency on + * PCI_SYNC_IN . + * + * CONFIG_PLL_PCI_TO_MEM_MULTIPLIER is only required on MPC8240 + * boards. It should be defined as the PCI to Memory Multiplier as + * documented in the MPC8240 Hardware Specs. + * + * Other mpc824x boards don't need CONFIG_PLL_PCI_TO_MEM_MULTIPLIER + * because they can determine it from the PCR. + * + * Gary Milliorn <gary.milliorn@motorola.com> (who should know since + * he designed the Sandpoint) told us that the PCR is not in all revs + * of the MPC8240 CPU, so it's not guaranteeable and we cannot do + * away with CONFIG_PLL_PCI_TO_MEM_MULTIPLIER altogether. + */ +/* ------------------------------------------------------------------------- */ + +/* This gives the PCI to Memory multiplier times 10 */ +/* The index is the value of PLL_CFG[0:4] */ +/* This is documented in the MPC8240/5 Hardware Specs */ + +short pll_pci_to_mem_multiplier[] = { +#if defined(CONFIG_MPC8240) + 30, 30, 10, 10, 20, 10, 0, 10, + 10, 0, 20, 0, 20, 0, 20, 0, + 30, 0, 15, 0, 20, 0, 20, 0, + 25, 0, 10, 0, 15, 15, 0, 0, +#elif defined(CONFIG_MPC8245) + 30, 30, 10, 10, 20, 10, 10, 10, + 10, 20, 20, 15, 20, 15, 20, 30, + 30, 40, 15, 40, 20, 25, 20, 40, + 25, 20, 10, 20, 15, 15, 15, 0, +#else +#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240) +#endif +}; + +#define CU824_PLL_STATE_REG 0xFE80002F +#define PCR 0x800000E2 + +/* ------------------------------------------------------------------------- */ + +/* compute the memory bus clock frequency */ +ulong get_bus_freq (ulong dummy) +{ + unsigned char pll_cfg; +#if defined(CONFIG_MPC8240) && !defined(CONFIG_CU824) + return (CONFIG_SYS_CLK_FREQ) * (CONFIG_PLL_PCI_TO_MEM_MULTIPLIER); +#elif defined(CONFIG_CU824) + pll_cfg = *(volatile unsigned char *) (CU824_PLL_STATE_REG); + pll_cfg &= 0x1f; +#else + CONFIG_READ_BYTE(PCR, pll_cfg); + pll_cfg = (pll_cfg >> 3) & 0x1f; +#endif + return ((CONFIG_SYS_CLK_FREQ) * pll_pci_to_mem_multiplier[pll_cfg] + 5) / 10; +} + + +/* ------------------------------------------------------------------------- */ + +/* This gives the Memory to CPU Core multiplier times 10 */ +/* The index is the value of PLLRATIO in HID1 */ +/* This is documented in the MPC8240 Hardware Specs */ +/* This is not documented for MPC8245 ? FIXME */ +short pllratio_to_factor[] = { + 0, 0, 0, 10, 20, 20, 25, 45, + 30, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 0, 0, 0, 45, + 30, 0, 40, 0, 0, 0, 35, 0, +}; + +/* compute the CPU and memory bus clock frequencies */ +int get_clocks (void) +{ + uint hid1 = mfspr(HID1); + hid1 = (hid1 >> (32-5)) & 0x1f; + gd->cpu_clk = (pllratio_to_factor[hid1] * get_bus_freq(0) + 5) + / 10; + gd->bus_clk = get_bus_freq(0); + return (0); +} diff --git a/arch/powerpc/cpu/mpc824x/start.S b/arch/powerpc/cpu/mpc824x/start.S new file mode 100644 index 0000000..f3f595a --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/start.S @@ -0,0 +1,766 @@ +/* + * 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 <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 +/* FP, Machine Check and Recoverable Interr. */ +#define MSR_KERNEL ( MSR_FP | MSR_ME | MSR_RI ) + +/* + * 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) +#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 " (", U_BOOT_DATE, " - ", U_BOOT_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, CONFIG_SYS_INIT_RAM_ADDR@h + ori r3, r3, CONFIG_SYS_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, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h + ori r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_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(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 */ + . = EXC_OFF_PROGRAM +ProgramCheck: + EXCEPTION_PROLOG(SRR0, SRR1) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException, + MSR_KERNEL, COPY_EE) + + /* No FPU on MPC8xx. This exception is not supposed to happen. + */ + STD_EXCEPTION(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) + STD_EXCEPTION(0xc00, SystemCall, UnknownException) + + 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, DebugException) + 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 */ + + GET_GOT + mr r3, r5 /* Destination Address */ +#ifdef CONFIG_SYS_RAMBOOT + lis r4, CONFIG_SYS_SDRAM_BASE@h /* Source Address */ + ori r4, r4, CONFIG_SYS_SDRAM_BASE@l +#else + lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */ + ori r4, r4, CONFIG_SYS_MONITOR_BASE@l +#endif + 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 + /* 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 + +4: +#if !defined(CONFIG_BMW) +/* Unlock the data cache and invalidate locked area */ + xor r0, r0, r0 + mtspr 1011, r0 + lis r4, CONFIG_SYS_INIT_RAM_ADDR@h + ori r4, r4, CONFIG_SYS_INIT_RAM_ADDR@l + li r0, 128 + mtctr r0 +41: + dcbi r0, r4 + addi r4, r4, 32 + bdnz 41b +#endif + +/* + * Now flush the cache: note that we must start from a cache aligned + * address. Otherwise we might miss one cache line. + */ + cmpwi r6,0 + add r5,r3,r5 + beq 7f /* Always flush prefetch queue in any case */ + subi r0,r6,1 + andc r3,r3,r0 + mr r4,r3 +5: dcbst 0,r4 + add r4,r4,r6 + cmplw r4,r5 + blt 5b + sync /* Wait for all dcbst to complete on bus */ + mr r4,r3 +6: icbi 0,r4 + add r4,r4,r6 + cmplw r4,r5 + blt 6b +7: sync /* Wait for all icbi to complete on bus */ + isync + +/* + * We are done. Do not return, instead branch to second part of board + * initialization, now running from RAM. + */ + + addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET + mtlr r0 + blr + +in_ram: + + /* + * Relocation Function, r12 point to got2+0x8000 + * + * Adjust got2 pointers, no need to check for 0, this code + * already puts a few entries in the table. + */ + li r0,__got2_entries@sectoff@l + la r3,GOT(_GOT2_TABLE_) + lwz r11,GOT(_GOT2_TABLE_) + mtctr r0 + sub r11,r3,r11 + addi r3,r3,-4 +1: lwzu r0,4(r3) + cmpwi r0,0 + beq- 2f + add r0,r0,r11 + stw r0,0(r3) +2: bdnz 1b + + /* + * Now adjust the fixups and the pointers to the fixups + * in case we need to move ourselves again. + */ + li r0,__fixup_entries@sectoff@l + lwz r3,GOT(_FIXUP_TABLE_) + cmpwi r0,0 + mtctr r0 + addi r3,r3,-4 + beq 4f +3: lwzu r4,4(r3) + lwzux r0,r4,r11 + add r0,r0,r11 + stw r10,0(r3) + stw r0,0(r4) + bdnz 3b +4: +clear_bss: + /* + * Now clear BSS segment + */ + lwz r3,GOT(__bss_start) + lwz r4,GOT(_end) + + cmplw 0, r3, r4 + beq 6f + + li r0, 0 +5: + stw r0, 0(r3) + addi r3, r3, 4 + cmplw 0, r3, r4 + blt 5b +6: + + mr r3, r9 /* Global Data pointer */ + mr r4, r10 /* Destination Address */ + bl board_init_r + + /* + * Copy exception vector code to low memory + * + * r3: dest_addr + * r7: source address, r8: end address, r9: target address + */ + .globl trap_init +trap_init: + mflr r4 /* save link register */ + GET_GOT + lwz r7, GOT(_start) + lwz r8, GOT(_end_of_vectors) + + li r9, 0x100 /* reset vector always at 0x100 */ + + cmplw 0, r7, r8 + bgelr /* return if r7>=r8 - just in case */ +1: + lwz r0, 0(r7) + stw r0, 0(r9) + addi r7, r7, 4 + addi r9, r9, 4 + cmplw 0, r7, r8 + bne 1b + + /* + * relocate `hdlr' and `int_return' entries + */ + li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET + li r8, Alignment - _start + EXC_OFF_SYS_RESET +2: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 2b + + li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET + bl trap_reloc + + li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET + bl trap_reloc + + li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET + li r8, SystemCall - _start + EXC_OFF_SYS_RESET +3: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 3b + + li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET + li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET +4: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 4b + + mtlr r4 /* restore link register */ + blr + + /* Setup the BAT registers. + */ +setup_bats: + lis r4, CONFIG_SYS_IBAT0L@h + ori r4, r4, CONFIG_SYS_IBAT0L@l + lis r3, CONFIG_SYS_IBAT0U@h + ori r3, r3, CONFIG_SYS_IBAT0U@l + mtspr IBAT0L, r4 + mtspr IBAT0U, r3 + isync + + lis r4, CONFIG_SYS_DBAT0L@h + ori r4, r4, CONFIG_SYS_DBAT0L@l + lis r3, CONFIG_SYS_DBAT0U@h + ori r3, r3, CONFIG_SYS_DBAT0U@l + mtspr DBAT0L, r4 + mtspr DBAT0U, r3 + isync + + lis r4, CONFIG_SYS_IBAT1L@h + ori r4, r4, CONFIG_SYS_IBAT1L@l + lis r3, CONFIG_SYS_IBAT1U@h + ori r3, r3, CONFIG_SYS_IBAT1U@l + mtspr IBAT1L, r4 + mtspr IBAT1U, r3 + isync + + lis r4, CONFIG_SYS_DBAT1L@h + ori r4, r4, CONFIG_SYS_DBAT1L@l + lis r3, CONFIG_SYS_DBAT1U@h + ori r3, r3, CONFIG_SYS_DBAT1U@l + mtspr DBAT1L, r4 + mtspr DBAT1U, r3 + isync + + lis r4, CONFIG_SYS_IBAT2L@h + ori r4, r4, CONFIG_SYS_IBAT2L@l + lis r3, CONFIG_SYS_IBAT2U@h + ori r3, r3, CONFIG_SYS_IBAT2U@l + mtspr IBAT2L, r4 + mtspr IBAT2U, r3 + isync + + lis r4, CONFIG_SYS_DBAT2L@h + ori r4, r4, CONFIG_SYS_DBAT2L@l + lis r3, CONFIG_SYS_DBAT2U@h + ori r3, r3, CONFIG_SYS_DBAT2U@l + mtspr DBAT2L, r4 + mtspr DBAT2U, r3 + isync + + lis r4, CONFIG_SYS_IBAT3L@h + ori r4, r4, CONFIG_SYS_IBAT3L@l + lis r3, CONFIG_SYS_IBAT3U@h + ori r3, r3, CONFIG_SYS_IBAT3U@l + mtspr IBAT3L, r4 + mtspr IBAT3U, r3 + isync + + lis r4, CONFIG_SYS_DBAT3L@h + ori r4, r4, CONFIG_SYS_DBAT3L@l + lis r3, CONFIG_SYS_DBAT3U@h + ori r3, r3, CONFIG_SYS_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 diff --git a/arch/powerpc/cpu/mpc824x/traps.c b/arch/powerpc/cpu/mpc824x/traps.c new file mode 100644 index 0000000..163b983 --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/traps.c @@ -0,0 +1,219 @@ +/* + * linux/arch/powerpc/kernel/traps.c + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@cs.anu.edu.au) + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include <common.h> +#include <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 0x00400000 + +/* + * 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; + } + + printf("Machine check in kernel mode.\n"); + printf("Caused by (from msr): "); + printf("regs %p ",regs); + switch( regs->msr & 0x000F0000) { + case (0x80000000>>12): + printf("Machine check signal - probably due to mm fault\n" + "with mmu off\n"); + break; + case (0x80000000>>13): + printf("Transfer error ack signal\n"); + break; + case (0x80000000>>14): + printf("Data parity signal\n"); + break; + case (0x80000000>>15): + printf("Address parity signal\n"); + break; + default: + printf("Unknown values in msr\n"); + } + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("machine check"); +} + +void +AlignmentException(struct pt_regs *regs) +{ + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Alignment Exception"); +} + +void +ProgramCheckException(struct pt_regs *regs) +{ + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Program Check Exception"); +} + +void +SoftEmuException(struct pt_regs *regs) +{ + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Software Emulation Exception"); +} + + +void +UnknownException(struct pt_regs *regs) +{ + 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/mpc824x/u-boot.lds b/arch/powerpc/cpu/mpc824x/u-boot.lds new file mode 100644 index 0000000..d1fcd7c --- /dev/null +++ b/arch/powerpc/cpu/mpc824x/u-boot.lds @@ -0,0 +1,122 @@ +/* + * (C) Copyright 2001-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +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/mpc824x/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 = .); +} |