diff options
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 000000000..2d79931e9 --- /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 000000000..a57ad12c4 --- /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 000000000..27c287351 --- /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 000000000..08f6a947f --- /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 000000000..395f7767d --- /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 000000000..2803f631c --- /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 000000000..57989969b --- /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 000000000..58f81c5df --- /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 000000000..ecbb42d0d --- /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 000000000..52d19aae8 --- /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 000000000..4877050ba --- /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 000000000..20794a2e8 --- /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 000000000..637ae4c1b --- /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 000000000..6264d189b --- /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 000000000..139c52cd3 --- /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 000000000..72aaec7b5 --- /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 000000000..fdcb9723c --- /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 000000000..f3f595af2 --- /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 000000000..163b98334 --- /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 000000000..d1fcd7c47 --- /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 = .); +} |