diff options
| author | Stefan Roese <sr@denx.de> | 2006-11-10 07:48:47 +0100 | 
|---|---|---|
| committer | Stefan Roese <sr@denx.de> | 2006-11-10 07:48:47 +0100 | 
| commit | dfc8a9ee0040e53ada125a3c52f241e37f09cf28 (patch) | |
| tree | 60fd3973150a4e6b3d9d129d117ecab71b5edabe /cpu | |
| parent | 5c912cb1c31266c66ca59b36f9b6f87296421d75 (diff) | |
| parent | 91650b3e4de688038d4f71279c44858e3e2c6870 (diff) | |
| download | olio-uboot-2014.01-dfc8a9ee0040e53ada125a3c52f241e37f09cf28.tar.xz olio-uboot-2014.01-dfc8a9ee0040e53ada125a3c52f241e37f09cf28.zip  | |
Merge with /home/stefan/git/u-boot/denx
Diffstat (limited to 'cpu')
80 files changed, 6991 insertions, 478 deletions
diff --git a/cpu/74xx_7xx/Makefile b/cpu/74xx_7xx/Makefile index e82fffcf0..fe905f31f 100644 --- a/cpu/74xx_7xx/Makefile +++ b/cpu/74xx_7xx/Makefile @@ -39,7 +39,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm1136/Makefile b/cpu/arm1136/Makefile index 5d2c7eb49..d5ac7d3fd 100644 --- a/cpu/arm1136/Makefile +++ b/cpu/arm1136/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm720t/Makefile b/cpu/arm720t/Makefile index 539a48c41..c97f32963 100644 --- a/cpu/arm720t/Makefile +++ b/cpu/arm720t/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm920t/Makefile b/cpu/arm920t/Makefile index 199fe0c2c..e02bc6ac8 100644 --- a/cpu/arm920t/Makefile +++ b/cpu/arm920t/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm920t/at91rm9200/Makefile b/cpu/arm920t/at91rm9200/Makefile index 26b0b94f2..8d4e478fb 100644 --- a/cpu/arm920t/at91rm9200/Makefile +++ b/cpu/arm920t/at91rm9200/Makefile @@ -35,7 +35,7 @@ OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))  all:	$(obj).depend $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm920t/imx/Makefile b/cpu/arm920t/imx/Makefile index e238fc01f..9207ec1bc 100644 --- a/cpu/arm920t/imx/Makefile +++ b/cpu/arm920t/imx/Makefile @@ -33,7 +33,7 @@ OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))  all:	$(obj).depend $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm920t/ks8695/Makefile b/cpu/arm920t/ks8695/Makefile index 6342435d9..7db947352 100644 --- a/cpu/arm920t/ks8695/Makefile +++ b/cpu/arm920t/ks8695/Makefile @@ -34,7 +34,7 @@ OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))  all:	$(obj).depend $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm920t/s3c24x0/Makefile b/cpu/arm920t/s3c24x0/Makefile index 557298eac..3a7c4b35f 100644 --- a/cpu/arm920t/s3c24x0/Makefile +++ b/cpu/arm920t/s3c24x0/Makefile @@ -34,7 +34,7 @@ OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))  all:	$(obj).depend $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm925t/Makefile b/cpu/arm925t/Makefile index 086b1a377..0d4912cd7 100644 --- a/cpu/arm925t/Makefile +++ b/cpu/arm925t/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm925t/omap925.c b/cpu/arm925t/omap925.c index ae62656f3..65dab9f88 100644 --- a/cpu/arm925t/omap925.c +++ b/cpu/arm925t/omap925.c @@ -25,40 +25,6 @@  #include <command.h>  #include <arm925t.h> -ushort gpioreserved; - -void gpioreserve(ushort mask) -{ -	gpioreserved |= mask; -} - -void gpiosetdir(ushort mask, ushort in) -{ -	*(ushort *)GPIO_DIR_CONTROL_REG = (*(ushort *)GPIO_DIR_CONTROL_REG & ~mask) | (in & mask); -} - - -void gpiosetout(ushort mask, ushort out) -{ -	ushort *r_ptr, r_val; - -	r_ptr = (ushort *)GPIO_DATA_OUTPUT_REG;	/* set pointer */ -	r_val = *r_ptr & ~mask;		/* get previous val, clear bits we want to change */ -	r_val |= (out & mask);		/* set specified bits in value + plus origional ones */ -	*r_ptr = r_val;			/* write it out */ -/* - * gcc screwed this one up :(. - * - * *(ushort *)GPIO_DATA_OUTPUT_REG = (*(ushort *)GPIO_DATA_OUTPUT_REG & ~mask) | (out & mask); - */ - -} - -void gpioinit(void) -{ -} - -  #define MIF_CONFIG_REG 0xFFFECC0C  #define FLASH_GLOBAL_CTRL_NWP 1 diff --git a/cpu/arm926ejs/Makefile b/cpu/arm926ejs/Makefile index a410c2f99..0facce470 100644 --- a/cpu/arm926ejs/Makefile +++ b/cpu/arm926ejs/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm926ejs/omap/Makefile b/cpu/arm926ejs/omap/Makefile index 7eca2f0d7..c335d5c86 100644 --- a/cpu/arm926ejs/omap/Makefile +++ b/cpu/arm926ejs/omap/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm926ejs/versatile/Makefile b/cpu/arm926ejs/versatile/Makefile index 7eca2f0d7..c335d5c86 100644 --- a/cpu/arm926ejs/versatile/Makefile +++ b/cpu/arm926ejs/versatile/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm946es/Makefile b/cpu/arm946es/Makefile index 5d2c7eb49..d5ac7d3fd 100644 --- a/cpu/arm946es/Makefile +++ b/cpu/arm946es/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/arm_intcm/Makefile b/cpu/arm_intcm/Makefile index 5d2c7eb49..d5ac7d3fd 100644 --- a/cpu/arm_intcm/Makefile +++ b/cpu/arm_intcm/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/at32ap/Makefile b/cpu/at32ap/Makefile new file mode 100644 index 000000000..f62ec8bc9 --- /dev/null +++ b/cpu/at32ap/Makefile @@ -0,0 +1,50 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright (C) 2005-2006 Atmel Corporation. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB	:= $(obj)lib$(CPU).a + +START	:= start.o +SOBJS	:= entry.o +COBJS	:= cpu.o hsdramc.o exception.o cache.o +COBJS	+= interrupts.o device.o pm.o pio.o +SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) +START	:= $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) + +$(LIB): $(OBJS) +	$(AR) $(ARFLAGS) $@ $^ + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/at32ap/at32ap7000/Makefile b/cpu/at32ap/at32ap7000/Makefile new file mode 100644 index 000000000..2ed74d250 --- /dev/null +++ b/cpu/at32ap/at32ap7000/Makefile @@ -0,0 +1,43 @@ +# +# Copyright (C) 2005-2006 Atmel Corporation +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB	:= $(obj)lib$(SOC).a + +COBJS	:= hebi.o devices.o +SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) +	$(AR) $(ARFLAGS) $@ $^ + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/at32ap/at32ap7000/devices.c b/cpu/at32ap/at32ap7000/devices.c new file mode 100644 index 000000000..8b216e906 --- /dev/null +++ b/cpu/at32ap/at32ap7000/devices.c @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2006 Atmel Corporation + * + * 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/arch/memory-map.h> +#include <asm/arch/platform.h> + +#include "../sm.h" + +#define ARRAY_SIZE(x)	(sizeof(x) / sizeof((x)[0])) + +const struct clock_domain chip_clock[] = { +	[CLOCK_CPU] = { +		.reg	= SM_PM_CPU_MASK, +		.id	= CLOCK_CPU, +		.bridge	= NO_DEVICE, +	}, +	[CLOCK_HSB] = { +		.reg	= SM_PM_HSB_MASK, +		.id	= CLOCK_HSB, +		.bridge	= NO_DEVICE, +	}, +	[CLOCK_PBA] = { +		.reg	= SM_PM_PBA_MASK, +		.id	= CLOCK_PBA, +		.bridge	= DEVICE_PBA_BRIDGE, +	}, +	[CLOCK_PBB] = { +		.reg	= SM_PM_PBB_MASK, +		.id	= CLOCK_PBB, +		.bridge	= DEVICE_PBB_BRIDGE, +	}, +}; + +static const struct resource hebi_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_HSB, 0 }, +		}, +	}, { +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBB, 13 }, +		}, +	}, { +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBB, 14 }, +		}, +	}, { +		.type	= RESOURCE_GPIO, +		.u	= { +			.gpio	= { 27, DEVICE_PIOE, GPIO_FUNC_A, 0 }, +		}, +	}, +}; +static const struct resource pba_bridge_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_HSB, 1 }, +		} +	}, { +		.type	= RESOURCE_CLOCK, +		.u	= { +			/* HSB-HSB Bridge */ +			.clock	= { CLOCK_HSB, 4 }, +		}, +	}, +}; +static const struct resource pbb_bridge_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_HSB, 2 }, +		}, +	}, +}; +static const struct resource hramc_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_HSB, 3 }, +		}, +	}, +}; +static const struct resource pioa_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBA, 10 }, +		}, +	}, +}; +static const struct resource piob_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBA, 11 }, +		}, +	}, +}; +static const struct resource pioc_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBA, 12 }, +		}, +	}, +}; +static const struct resource piod_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBA, 13 }, +		}, +	}, +}; +static const struct resource pioe_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBA, 14 }, +		}, +	}, +}; +static const struct resource sm_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBB, 0 }, +		}, +	}, +}; +static const struct resource intc_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock = { CLOCK_PBB, 1 }, +		}, +	}, +}; +static const struct resource hmatrix_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock = { CLOCK_PBB, 2 }, +		}, +	}, +}; +#if defined(CFG_HPDC) +static const struct resource hpdc_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBA, 16 }, +		}, +	}, +}; +#endif +#if defined(CFG_MACB0) +static const struct resource macb0_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_HSB, 8 }, +		}, +	}, { +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBB, 6 }, +		}, +	}, { +		.type	= RESOURCE_GPIO, +		.u	= { +			.gpio	= { 19, DEVICE_PIOC, GPIO_FUNC_A, 0 }, +		}, +	}, +}; +#endif +#if defined(CFG_MACB1) +static const struct resource macb1_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_HSB, 9 }, +		}, +	}, { +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBB, 7 }, +		}, +	}, { +		.type	= RESOURCE_GPIO, +		.u	= { +			.gpio	= { 12, DEVICE_PIOC, GPIO_FUNC_B, 19 }, +		}, +	}, { +		.type	= RESOURCE_GPIO, +		.u	= { +			.gpio	= { 14, DEVICE_PIOD, GPIO_FUNC_B, 2 }, +		}, +	}, +}; +#endif +#if defined(CFG_LCDC) +static const struct resource lcdc_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_HSB, 7 }, +		}, +	}, +}; +#endif +#if defined(CFG_USART0) +static const struct resource usart0_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBA, 3 }, +		}, +	}, { +		.type	= RESOURCE_GPIO, +		.u	= { +			.gpio = { 2, DEVICE_PIOA, GPIO_FUNC_B, 8 }, +		}, +	}, +}; +#endif +#if defined(CFG_USART1) +static const struct resource usart1_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBA, 4 }, +		}, +	}, { +		.type	= RESOURCE_GPIO, +		.u	= { +			.gpio = { 2, DEVICE_PIOA, GPIO_FUNC_A, 17 }, +		}, +	}, +}; +#endif +#if defined(CFG_USART2) +static const struct resource usart2_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBA, 5 }, +		}, +	}, { +		.type	= RESOURCE_GPIO, +		.u	= { +			.gpio = { 2, DEVICE_PIOB, GPIO_FUNC_B, 26 }, +		}, +	}, +}; +#endif +#if defined(CFG_USART3) +static const struct resource usart3_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBA, 6 }, +		}, +	}, { +		.type	= RESOURCE_GPIO, +		.u	= { +			.gpio = { 2, DEVICE_PIOB, GPIO_FUNC_B, 17 }, +		}, +	}, +}; +#endif +#if defined(CFG_MMCI) +static const struct resource mmci_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_PBB, 9 }, +		}, +	}, { +		.type	= RESOURCE_GPIO, +		.u	= { +			.gpio = { 6, DEVICE_PIOA, GPIO_FUNC_A, 10 }, +		}, +	}, +}; +#endif +#if defined(CFG_DMAC) +static const struct resource dmac_resource[] = { +	{ +		.type	= RESOURCE_CLOCK, +		.u	= { +			.clock	= { CLOCK_HSB, 10 }, +		}, +	}, +}; +#endif + +const struct device chip_device[] = { +	[DEVICE_HEBI] = { +		.regs		= (void *)HSMC_BASE, +		.nr_resources	= ARRAY_SIZE(hebi_resource), +		.resource	= hebi_resource, +	}, +	[DEVICE_PBA_BRIDGE] = { +		.nr_resources	= ARRAY_SIZE(pba_bridge_resource), +		.resource	= pba_bridge_resource, +	}, +	[DEVICE_PBB_BRIDGE] = { +		.nr_resources	= ARRAY_SIZE(pbb_bridge_resource), +		.resource	= pbb_bridge_resource, +	}, +	[DEVICE_HRAMC] = { +		.nr_resources	= ARRAY_SIZE(hramc_resource), +		.resource	= hramc_resource, +	}, +	[DEVICE_PIOA] = { +		.regs		= (void *)PIOA_BASE, +		.nr_resources	= ARRAY_SIZE(pioa_resource), +		.resource	= pioa_resource, +	}, +	[DEVICE_PIOB] = { +		.regs		= (void *)PIOB_BASE, +		.nr_resources	= ARRAY_SIZE(piob_resource), +		.resource	= piob_resource, +	}, +	[DEVICE_PIOC] = { +		.regs		= (void *)PIOC_BASE, +		.nr_resources	= ARRAY_SIZE(pioc_resource), +		.resource	= pioc_resource, +	}, +	[DEVICE_PIOD] = { +		.regs		= (void *)PIOD_BASE, +		.nr_resources	= ARRAY_SIZE(piod_resource), +		.resource	= piod_resource, +	}, +	[DEVICE_PIOE] = { +		.regs		= (void *)PIOE_BASE, +		.nr_resources	= ARRAY_SIZE(pioe_resource), +		.resource	= pioe_resource, +	}, +	[DEVICE_SM] = { +		.regs		= (void *)SM_BASE, +		.nr_resources	= ARRAY_SIZE(sm_resource), +		.resource	= sm_resource, +	}, +	[DEVICE_INTC] = { +		.regs		= (void *)INTC_BASE, +		.nr_resources	= ARRAY_SIZE(intc_resource), +		.resource	= intc_resource, +	}, +	[DEVICE_HMATRIX] = { +		.regs		= (void *)HMATRIX_BASE, +		.nr_resources	= ARRAY_SIZE(hmatrix_resource), +		.resource	= hmatrix_resource, +	}, +#if defined(CFG_HPDC) +	[DEVICE_HPDC] = { +		.nr_resources	= ARRAY_SIZE(hpdc_resource), +		.resource	= hpdc_resource, +	}, +#endif +#if defined(CFG_MACB0) +	[DEVICE_MACB0] = { +		.regs		= (void *)MACB0_BASE, +		.nr_resources	= ARRAY_SIZE(macb0_resource), +		.resource	= macb0_resource, +	}, +#endif +#if defined(CFG_MACB1) +	[DEVICE_MACB1] = { +		.regs		= (void *)MACB1_BASE, +		.nr_resources	= ARRAY_SIZE(macb1_resource), +		.resource	= macb1_resource, +	}, +#endif +#if defined(CFG_LCDC) +	[DEVICE_LCDC] = { +		.nr_resources	= ARRAY_SIZE(lcdc_resource), +		.resource	= lcdc_resource, +	}, +#endif +#if defined(CFG_USART0) +	[DEVICE_USART0] = { +		.regs		= (void *)USART0_BASE, +		.nr_resources	= ARRAY_SIZE(usart0_resource), +		.resource	= usart0_resource, +	}, +#endif +#if defined(CFG_USART1) +	[DEVICE_USART1] = { +		.regs		= (void *)USART1_BASE, +		.nr_resources	= ARRAY_SIZE(usart1_resource), +		.resource	= usart1_resource, +	}, +#endif +#if defined(CFG_USART2) +	[DEVICE_USART2] = { +		.regs		= (void *)USART2_BASE, +		.nr_resources	= ARRAY_SIZE(usart2_resource), +		.resource	= usart2_resource, +	}, +#endif +#if defined(CFG_USART3) +	[DEVICE_USART3] = { +		.regs		= (void *)USART3_BASE, +		.nr_resources	= ARRAY_SIZE(usart3_resource), +		.resource	= usart3_resource, +	}, +#endif +#if defined(CFG_MMCI) +	[DEVICE_MMCI] = { +		.regs		= (void *)MMCI_BASE, +		.nr_resources	= ARRAY_SIZE(mmci_resource), +		.resource	= mmci_resource, +	}, +#endif +#if defined(CFG_DMAC) +	[DEVICE_DMAC] = { +		.regs		= (void *)DMAC_BASE, +		.nr_resources	= ARRAY_SIZE(dmac_resource), +		.resource	= dmac_resource, +	}, +#endif +}; diff --git a/cpu/at32ap/at32ap7000/hebi.c b/cpu/at32ap/at32ap7000/hebi.c new file mode 100644 index 000000000..3b32adf1e --- /dev/null +++ b/cpu/at32ap/at32ap7000/hebi.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2006 Atmel Corporation + * + * 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/io.h> + +#include <asm/arch/hmatrix2.h> +#include <asm/arch/memory-map.h> +#include <asm/arch/platform.h> + +void cpu_enable_sdram(void) +{ +	const struct device *hmatrix; + +	hmatrix = get_device(DEVICE_HMATRIX); + +	/* Set the SDRAM_ENABLE bit in the HEBI SFR */ +	hmatrix2_writel(hmatrix, SFR4, 1 << 1); +} diff --git a/cpu/at32ap/cache.c b/cpu/at32ap/cache.c new file mode 100644 index 000000000..41fb5aa04 --- /dev/null +++ b/cpu/at32ap/cache.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * 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/cacheflush.h> + +void dcache_clean_range(volatile void *start, size_t size) +{ +	unsigned long v, begin, end, linesz; + +	linesz = CFG_DCACHE_LINESZ; + +	/* You asked for it, you got it */ +	begin = (unsigned long)start & ~(linesz - 1); +	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); + +	for (v = begin; v < end; v += linesz) +		dcache_clean_line((void *)v); + +	sync_write_buffer(); +} + +void dcache_invalidate_range(volatile void *start, size_t size) +{ +	unsigned long v, begin, end, linesz; + +	linesz = CFG_DCACHE_LINESZ; + +	/* You asked for it, you got it */ +	begin = (unsigned long)start & ~(linesz - 1); +	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); + +	for (v = begin; v < end; v += linesz) +		dcache_invalidate_line((void *)v); +} + +void dcache_flush_range(volatile void *start, size_t size) +{ +	unsigned long v, begin, end, linesz; + +	linesz = CFG_DCACHE_LINESZ; + +	/* You asked for it, you got it */ +	begin = (unsigned long)start & ~(linesz - 1); +	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); + +	for (v = begin; v < end; v += linesz) +		dcache_flush_line((void *)v); + +	sync_write_buffer(); +} + +void icache_invalidate_range(volatile void *start, size_t size) +{ +	unsigned long v, begin, end, linesz; + +	linesz = CFG_ICACHE_LINESZ; + +	/* You asked for it, you got it */ +	begin = (unsigned long)start & ~(linesz - 1); +	end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); + +	for (v = begin; v < end; v += linesz) +		icache_invalidate_line((void *)v); +} + +/* + * This is called after loading something into memory.  We need to + * make sure that everything that was loaded is actually written to + * RAM, and that the icache will look for it. Cleaning the dcache and + * invalidating the icache will do the trick. + */ +void  flush_cache (unsigned long start_addr, unsigned long size) +{ +	dcache_clean_range((void *)start_addr, size); +	icache_invalidate_range((void *)start_addr, size); +} diff --git a/cpu/at32ap/config.mk b/cpu/at32ap/config.mk new file mode 100644 index 000000000..1c1216922 --- /dev/null +++ b/cpu/at32ap/config.mk @@ -0,0 +1,22 @@ +# +# Copyright (C) 2005-2006 Atmel Corporation +# +# 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       += -mcpu=ap7000 diff --git a/cpu/at32ap/cpu.c b/cpu/at32ap/cpu.c new file mode 100644 index 000000000..37e3ea040 --- /dev/null +++ b/cpu/at32ap/cpu.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * 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 <command.h> + +#include <asm/io.h> +#include <asm/sections.h> +#include <asm/sysreg.h> + +#include <asm/arch/memory-map.h> +#include <asm/arch/platform.h> + +#include "hsmc3.h" + +DECLARE_GLOBAL_DATA_PTR; + +int cpu_init(void) +{ +	const struct device *hebi; +	extern void _evba(void); +	char *p; + +	gd->cpu_hz = CFG_OSC0_HZ; + +	/* fff03400: 00010001 04030402 00050005 10011103 */ +	hebi = get_device(DEVICE_HEBI); +	hsmc3_writel(hebi, MODE0, 0x00031103); +	hsmc3_writel(hebi, CYCLE0, 0x000c000d); +	hsmc3_writel(hebi, PULSE0, 0x0b0a0906); +	hsmc3_writel(hebi, SETUP0, 0x00010002); + +	pm_init(); + +	sysreg_write(EVBA, (unsigned long)&_evba); +	asm volatile("csrf	%0" : : "i"(SYSREG_EM_OFFSET)); +	gd->console_uart = get_device(CFG_CONSOLE_UART_DEV); + +	/* Lock everything that mess with the flash in the icache */ +	for (p = __flashprog_start; p <= (__flashprog_end + CFG_ICACHE_LINESZ); +	     p += CFG_ICACHE_LINESZ) +		asm volatile("cache %0, 0x02" : "=m"(*p) :: "memory"); + +	return 0; +} + +void prepare_to_boot(void) +{ +	/* Flush both caches and the write buffer */ +	asm volatile("cache  %0[4], 010\n\t" +		     "cache  %0[0], 000\n\t" +		     "sync   0" : : "r"(0) : "memory"); +} + +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	/* This will reset the CPU core, caches, MMU and all internal busses */ +	__builtin_mtdr(8, 1 << 13);	/* set DC:DBE */ +	__builtin_mtdr(8, 1 << 30);	/* set DC:RES */ + +	/* Flush the pipeline before we declare it a failure */ +	asm volatile("sub   pc, pc, -4"); + +	return -1; +} diff --git a/cpu/at32ap/device.c b/cpu/at32ap/device.c new file mode 100644 index 000000000..89914b6b5 --- /dev/null +++ b/cpu/at32ap/device.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2006 Atmel Corporation + * + * 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/arch/platform.h> + +#include "sm.h" + +struct device_state { +	int refcount; +}; + +static struct device_state device_state[NR_DEVICES]; + +static int claim_resource(const struct resource *res) +{ +	int ret = 0; + +	switch (res->type) { +	case RESOURCE_GPIO: +		ret = gpio_set_func(res->u.gpio.gpio_dev, +				    res->u.gpio.start, +				    res->u.gpio.nr_pins, +				    res->u.gpio.func); +		break; +	case RESOURCE_CLOCK: +		ret = pm_enable_clock(res->u.clock.id, res->u.clock.index); +		break; +	} + +	return ret; +} + +static void free_resource(const struct resource *res) +{ +	switch (res->type) { +	case RESOURCE_GPIO: +		gpio_free(res->u.gpio.gpio_dev, res->u.gpio.start, +			  res->u.gpio.nr_pins); +		break; +	case RESOURCE_CLOCK: +		pm_disable_clock(res->u.clock.id, res->u.clock.index); +		break; +	} +} + +static int init_dev(const struct device *dev) +{ +	unsigned int i; +	int ret = 0; + +	for (i = 0; i < dev->nr_resources; i++) { +		ret = claim_resource(&dev->resource[i]); +		if (ret) +			goto cleanup; +	} + +	return 0; + +cleanup: +	while (i--) +		free_resource(&dev->resource[i]); + +	return ret; +} + +const struct device *get_device(enum device_id devid) +{ +	struct device_state *devstate; +	const struct device *dev; +	unsigned long flags; +	int initialized = 0; +	int ret = 0; + +	devstate = &device_state[devid]; +	dev = &chip_device[devid]; + +	flags = disable_interrupts(); +	if (devstate->refcount++) +		initialized = 1; +	if (flags) +		enable_interrupts(); + +	if (!initialized) +		ret = init_dev(dev); + +	return ret ? NULL : dev; +} + +void put_device(const struct device *dev) +{ +	struct device_state *devstate; +	unsigned long devid, flags; + +	devid = (unsigned long)(dev - chip_device) / sizeof(struct device); +	devstate = &device_state[devid]; + +	flags = disable_interrupts(); +	devstate--; +	if (!devstate) { +		unsigned int i; +		for (i = 0; i < dev->nr_resources; i++) +			free_resource(&dev->resource[i]); +	} +	if (flags) +		enable_interrupts(); +} diff --git a/cpu/at32ap/entry.S b/cpu/at32ap/entry.S new file mode 100644 index 000000000..b52d798be --- /dev/null +++ b/cpu/at32ap/entry.S @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * 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 <asm/sysreg.h> +#include <asm/ptrace.h> + +	.section .text.exception,"ax" +	.global	_evba +	.type	_evba,@function +	.align	10 +_evba: +	.irp	x,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 +	.align	2 +	rjmp	unknown_exception +	.endr + +	.global	timer_interrupt_handler +	.type	timer_interrupt_handler,@function +	.align	2 +timer_interrupt_handler: +	/* +	 * Increment timer_overflow and re-write COMPARE with 0xffffffff. +	 * +	 * We're running at interrupt level 3, so we don't need to save +	 * r8-r12 or lr to the stack. +	 */ +	mov	r8, lo(timer_overflow) +	orh	r8, hi(timer_overflow) +	ld.w	r9, r8[0] +	mov	r10, -1 +	mtsr	SYSREG_COMPARE, r10 +	sub	r9, -1 +	st.w	r8[0], r9 +	rete + +	.type	unknown_exception, @function +unknown_exception: +	pushm	r0-r12 +	sub	r8, sp, REG_R12 - REG_R0 - 4 +	mov	r9, lr +	mfsr	r10, SYSREG_RAR_EX +	mfsr	r11, SYSREG_RSR_EX +	pushm	r8-r11 +	mfsr	r12, SYSREG_ECR +	mov	r11, sp +	rcall	do_unknown_exception +1:	rjmp	1b diff --git a/cpu/at32ap/exception.c b/cpu/at32ap/exception.c new file mode 100644 index 000000000..4123c4461 --- /dev/null +++ b/cpu/at32ap/exception.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * 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/sysreg.h> +#include <asm/ptrace.h> + +static const char * const cpu_modes[8] = { +	"Application", "Supervisor", "Interrupt level 0", "Interrupt level 1", +	"Interrupt level 2", "Interrupt level 3", "Exception", "NMI" +}; + +static void dump_mem(const char *str, unsigned long bottom, unsigned long top) +{ +	unsigned long p; +	int i; + +	printf("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); + +	for (p = bottom & ~31; p < top; ) { +		printf("%04lx: ", p & 0xffff); + +		for (i = 0; i < 8; i++, p += 4) { +			unsigned int val; + +			if (p < bottom || p >= top) +				printf("         "); +			else { +				val = *(unsigned long *)p; +				printf("%08x ", val); +			} +		} +		printf("\n"); +	} +} + +void do_unknown_exception(unsigned int ecr, struct pt_regs *regs) +{ +	unsigned int mode; + +	printf("\n *** Unhandled exception %u at PC=0x%08lx\n", ecr, regs->pc); + +	switch (ecr) { +	case ECR_BUS_ERROR_WRITE: +	case ECR_BUS_ERROR_READ: +		printf("Bus error at address 0x%08lx\n", +		       sysreg_read(BEAR)); +		break; +	case ECR_TLB_MULTIPLE: +	case ECR_ADDR_ALIGN_X: +	case ECR_PROTECTION_X: +	case ECR_ADDR_ALIGN_R: +	case ECR_ADDR_ALIGN_W: +	case ECR_PROTECTION_R: +	case ECR_PROTECTION_W: +	case ECR_DTLB_MODIFIED: +	case ECR_TLB_MISS_X: +	case ECR_TLB_MISS_R: +	case ECR_TLB_MISS_W: +		printf("MMU exception at address 0x%08lx\n", +		       sysreg_read(TLBEAR)); +		break; +	} + +	printf("   pc: %08lx    lr: %08lx    sp: %08lx   r12: %08lx\n", +	       regs->pc, regs->lr, regs->sp, regs->r12); +	printf("  r11: %08lx   r10: %08lx    r9: %08lx    r8: %08lx\n", +	       regs->r11, regs->r10, regs->r9, regs->r8); +	printf("   r7: %08lx    r6: %08lx    r5: %08lx    r4: %08lx\n", +	       regs->r7, regs->r6, regs->r5, regs->r4); +	printf("   r3: %08lx    r2: %08lx    r1: %08lx    r0: %08lx\n", +	       regs->r3, regs->r2, regs->r1, regs->r0); +	printf("Flags: %c%c%c%c%c\n", +	       regs->sr & SR_Q ? 'Q' : 'q', +	       regs->sr & SR_V ? 'V' : 'v', +	       regs->sr & SR_N ? 'N' : 'n', +	       regs->sr & SR_Z ? 'Z' : 'z', +	       regs->sr & SR_C ? 'C' : 'c'); +	printf("Mode bits: %c%c%c%c%c%c%c%c%c\n", +	       regs->sr & SR_H ? 'H' : 'h', +	       regs->sr & SR_R ? 'R' : 'r', +	       regs->sr & SR_J ? 'J' : 'j', +	       regs->sr & SR_EM ? 'E' : 'e', +	       regs->sr & SR_I3M ? '3' : '.', +	       regs->sr & SR_I2M ? '2' : '.', +	       regs->sr & SR_I1M ? '1' : '.', +	       regs->sr & SR_I0M ? '0' : '.', +	       regs->sr & SR_GM ? 'G' : 'g'); +	mode = (regs->sr >> SYSREG_M0_OFFSET) & 7; +	printf("CPU Mode: %s\n", cpu_modes[mode]); + +	/* Avoid exception loops */ +	if (regs->sp >= CFG_INIT_SP_ADDR +	    || regs->sp < (CFG_INIT_SP_ADDR - CONFIG_STACKSIZE)) +		printf("\nStack pointer seems bogus, won't do stack dump\n"); +	else +		dump_mem("\nStack: ", regs->sp, CFG_INIT_SP_ADDR); + +	panic("Unhandled exception\n"); +} diff --git a/cpu/at32ap/hsdramc.c b/cpu/at32ap/hsdramc.c new file mode 100644 index 000000000..f36da3545 --- /dev/null +++ b/cpu/at32ap/hsdramc.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * 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> + +#ifdef CFG_HSDRAMC +#include <asm/io.h> +#include <asm/sdram.h> + +#include <asm/arch/platform.h> + +#include "hsdramc1.h" + +struct hsdramc { +	const struct device *hebi; +	void *regs; +}; + +static struct hsdramc hsdramc; + +unsigned long sdram_init(const struct sdram_info *info) +{ +	unsigned long *sdram = (unsigned long *)uncached(info->phys_addr); +	unsigned long sdram_size; +	unsigned long tmp; +	unsigned long bus_hz; +	unsigned int i; + +	hsdramc.hebi = get_device(DEVICE_HEBI); +	if (!hsdramc.hebi) +		return 0; + +	/* FIXME: Both of these lines are complete hacks */ +	hsdramc.regs = hsdramc.hebi->regs + 0x400; +	bus_hz = pm_get_clock_freq(hsdramc.hebi->resource[0].u.clock.id); + +	cpu_enable_sdram(); + +	tmp = (HSDRAMC1_BF(NC, info->col_bits - 8) +	       | HSDRAMC1_BF(NR, info->row_bits - 11) +	       | HSDRAMC1_BF(NB, info->bank_bits - 1) +	       | HSDRAMC1_BF(CAS, info->cas) +	       | HSDRAMC1_BF(TWR, info->twr) +	       | HSDRAMC1_BF(TRC, info->trc) +	       | HSDRAMC1_BF(TRP, info->trp) +	       | HSDRAMC1_BF(TRCD, info->trcd) +	       | HSDRAMC1_BF(TRAS, info->tras) +	       | HSDRAMC1_BF(TXSR, info->txsr)); + +#ifdef CFG_SDRAM_16BIT +	tmp |= HSDRAMC1_BIT(DBW); +	sdram_size = 1 << (info->row_bits + info->col_bits +			   + info->bank_bits + 1); +#else +	sdram_size = 1 << (info->row_bits + info->col_bits +			   + info->bank_bits + 2); +#endif + +	hsdramc1_writel(&hsdramc, CR, tmp); + +	/* +	 * Initialization sequence for SDRAM, from the data sheet: +	 * +	 * 1. A minimum pause of 200 us is provided to precede any +	 *    signal toggle. +	 */ +	udelay(200); + +	/* +	 * 2. A Precharge All command is issued to the SDRAM +	 */ +	hsdramc1_writel(&hsdramc, MR, HSDRAMC1_MODE_BANKS_PRECHARGE); +	hsdramc1_readl(&hsdramc, MR); +	writel(0, sdram); + +	/* +	 * 3. Eight auto-refresh (CBR) cycles are provided +	 */ +	hsdramc1_writel(&hsdramc, MR, HSDRAMC1_MODE_AUTO_REFRESH); +	hsdramc1_readl(&hsdramc, MR); +	for (i = 0; i < 8; i++) +		writel(0, sdram); + +	/* +	 * 4. A mode register set (MRS) cycle is issued to program +	 *    SDRAM parameters, in particular CAS latency and burst +	 *    length. +	 * +	 * CAS from info struct, burst length 1, serial burst type +	 */ +	hsdramc1_writel(&hsdramc, MR, HSDRAMC1_MODE_LOAD_MODE); +	hsdramc1_readl(&hsdramc, MR); +	writel(0, sdram + (info->cas << 4)); + +	/* +	 * 5. A Normal Mode command is provided, 3 clocks after tMRD +	 *    is met. +	 * +	 * From the timing diagram, it looks like tMRD is 3 +	 * cycles...try a dummy read from the peripheral bus. +	 */ +	hsdramc1_readl(&hsdramc, MR); +	hsdramc1_writel(&hsdramc, MR, HSDRAMC1_MODE_NORMAL); +	hsdramc1_readl(&hsdramc, MR); +	writel(0, sdram); + +	/* +	 * 6. Write refresh rate into SDRAMC refresh timer count +	 *    register (refresh rate = timing between refresh cycles). +	 * +	 * 15.6 us is a typical value for a burst of length one +	 */ +	hsdramc1_writel(&hsdramc, TR, (156 * (bus_hz / 1000)) / 10000); + +	printf("SDRAM: %u MB at address 0x%08lx\n", +	       sdram_size >> 20, info->phys_addr); + +	printf("Testing SDRAM..."); +	for (i = 0; i < sdram_size / 4; i++) +		sdram[i] = i; + +	for (i = 0; i < sdram_size / 4; i++) { +		tmp = sdram[i]; +		if (tmp != i) { +			printf("FAILED at address 0x%08lx\n", +			       info->phys_addr + i * 4); +			printf("SDRAM: read 0x%lx, expected 0x%lx\n", tmp, i); +			return 0; +		} +	} + +	puts("OK\n"); + +	return sdram_size; +} + +#endif /* CFG_HSDRAMC */ diff --git a/cpu/at32ap/hsdramc1.h b/cpu/at32ap/hsdramc1.h new file mode 100644 index 000000000..ce229bca1 --- /dev/null +++ b/cpu/at32ap/hsdramc1.h @@ -0,0 +1,143 @@ +/* + * Register definitions for SDRAM Controller + */ +#ifndef __ASM_AVR32_HSDRAMC1_H__ +#define __ASM_AVR32_HSDRAMC1_H__ + +/* HSDRAMC1 register offsets */ +#define HSDRAMC1_MR				0x0000 +#define HSDRAMC1_TR				0x0004 +#define HSDRAMC1_CR				0x0008 +#define HSDRAMC1_HSR				0x000c +#define HSDRAMC1_LPR				0x0010 +#define HSDRAMC1_IER				0x0014 +#define HSDRAMC1_IDR				0x0018 +#define HSDRAMC1_IMR				0x001c +#define HSDRAMC1_ISR				0x0020 +#define HSDRAMC1_MDR				0x0024 +#define HSDRAMC1_VERSION			0x00fc + +/* Bitfields in MR */ +#define HSDRAMC1_MODE_OFFSET			0 +#define HSDRAMC1_MODE_SIZE			3 + +/* Bitfields in TR */ +#define HSDRAMC1_COUNT_OFFSET			0 +#define HSDRAMC1_COUNT_SIZE			12 + +/* Bitfields in CR */ +#define HSDRAMC1_NC_OFFSET			0 +#define HSDRAMC1_NC_SIZE			2 +#define HSDRAMC1_NR_OFFSET			2 +#define HSDRAMC1_NR_SIZE			2 +#define HSDRAMC1_NB_OFFSET			4 +#define HSDRAMC1_NB_SIZE			1 +#define HSDRAMC1_CAS_OFFSET			5 +#define HSDRAMC1_CAS_SIZE			2 +#define HSDRAMC1_DBW_OFFSET			7 +#define HSDRAMC1_DBW_SIZE			1 +#define HSDRAMC1_TWR_OFFSET			8 +#define HSDRAMC1_TWR_SIZE			4 +#define HSDRAMC1_TRC_OFFSET			12 +#define HSDRAMC1_TRC_SIZE			4 +#define HSDRAMC1_TRP_OFFSET			16 +#define HSDRAMC1_TRP_SIZE			4 +#define HSDRAMC1_TRCD_OFFSET			20 +#define HSDRAMC1_TRCD_SIZE			4 +#define HSDRAMC1_TRAS_OFFSET			24 +#define HSDRAMC1_TRAS_SIZE			4 +#define HSDRAMC1_TXSR_OFFSET			28 +#define HSDRAMC1_TXSR_SIZE			4 + +/* Bitfields in HSR */ +#define HSDRAMC1_DA_OFFSET			0 +#define HSDRAMC1_DA_SIZE			1 + +/* Bitfields in LPR */ +#define HSDRAMC1_LPCB_OFFSET			0 +#define HSDRAMC1_LPCB_SIZE			2 +#define HSDRAMC1_PASR_OFFSET			4 +#define HSDRAMC1_PASR_SIZE			3 +#define HSDRAMC1_TCSR_OFFSET			8 +#define HSDRAMC1_TCSR_SIZE			2 +#define HSDRAMC1_DS_OFFSET			10 +#define HSDRAMC1_DS_SIZE			2 +#define HSDRAMC1_TIMEOUT_OFFSET			12 +#define HSDRAMC1_TIMEOUT_SIZE			2 + +/* Bitfields in IDR */ +#define HSDRAMC1_RES_OFFSET			0 +#define HSDRAMC1_RES_SIZE			1 + +/* Bitfields in MDR */ +#define HSDRAMC1_MD_OFFSET			0 +#define HSDRAMC1_MD_SIZE			2 + +/* Bitfields in VERSION */ +#define HSDRAMC1_VERSION_OFFSET			0 +#define HSDRAMC1_VERSION_SIZE			12 +#define HSDRAMC1_MFN_OFFSET			16 +#define HSDRAMC1_MFN_SIZE			3 + +/* Constants for MODE */ +#define HSDRAMC1_MODE_NORMAL			0 +#define HSDRAMC1_MODE_NOP			1 +#define HSDRAMC1_MODE_BANKS_PRECHARGE		2 +#define HSDRAMC1_MODE_LOAD_MODE			3 +#define HSDRAMC1_MODE_AUTO_REFRESH		4 +#define HSDRAMC1_MODE_EXT_LOAD_MODE		5 +#define HSDRAMC1_MODE_POWER_DOWN		6 + +/* Constants for NC */ +#define HSDRAMC1_NC_8_COLUMN_BITS		0 +#define HSDRAMC1_NC_9_COLUMN_BITS		1 +#define HSDRAMC1_NC_10_COLUMN_BITS		2 +#define HSDRAMC1_NC_11_COLUMN_BITS		3 + +/* Constants for NR */ +#define HSDRAMC1_NR_11_ROW_BITS			0 +#define HSDRAMC1_NR_12_ROW_BITS			1 +#define HSDRAMC1_NR_13_ROW_BITS			2 + +/* Constants for NB */ +#define HSDRAMC1_NB_TWO_BANKS			0 +#define HSDRAMC1_NB_FOUR_BANKS			1 + +/* Constants for CAS */ +#define HSDRAMC1_CAS_ONE_CYCLE			1 +#define HSDRAMC1_CAS_TWO_CYCLES			2 + +/* Constants for DBW */ +#define HSDRAMC1_DBW_32_BITS			0 +#define HSDRAMC1_DBW_16_BITS			1 + +/* Constants for TIMEOUT */ +#define HSDRAMC1_TIMEOUT_AFTER_END		0 +#define HSDRAMC1_TIMEOUT_64_CYC_AFTER_END	1 +#define HSDRAMC1_TIMEOUT_128_CYC_AFTER_END	2 + +/* Constants for MD */ +#define HSDRAMC1_MD_SDRAM			0 +#define HSDRAMC1_MD_LOW_POWER_SDRAM		1 + +/* Bit manipulation macros */ +#define HSDRAMC1_BIT(name)					\ +	(1 << HSDRAMC1_##name##_OFFSET) +#define HSDRAMC1_BF(name,value)					\ +	(((value) & ((1 << HSDRAMC1_##name##_SIZE) - 1))	\ +	 << HSDRAMC1_##name##_OFFSET) +#define HSDRAMC1_BFEXT(name,value)				\ +	(((value) >> HSDRAMC1_##name##_OFFSET)			\ +	 & ((1 << HSDRAMC1_##name##_SIZE) - 1)) +#define HSDRAMC1_BFINS(name,value,old)				\ +	(((old) & ~(((1 << HSDRAMC1_##name##_SIZE) - 1)		\ +		    << HSDRAMC1_##name##_OFFSET))		\ +	 | HSDRAMC1_BF(name,value)) + +/* Register access macros */ +#define hsdramc1_readl(port,reg)				\ +	readl((port)->regs + HSDRAMC1_##reg) +#define hsdramc1_writel(port,reg,value)				\ +	writel((value), (port)->regs + HSDRAMC1_##reg) + +#endif /* __ASM_AVR32_HSDRAMC1_H__ */ diff --git a/cpu/at32ap/hsmc3.h b/cpu/at32ap/hsmc3.h new file mode 100644 index 000000000..ec78cee71 --- /dev/null +++ b/cpu/at32ap/hsmc3.h @@ -0,0 +1,126 @@ +/* + * Register definitions for Static Memory Controller + */ +#ifndef __CPU_AT32AP_HSMC3_H__ +#define __CPU_AT32AP_HSMC3_H__ + +/* HSMC3 register offsets */ +#define HSMC3_SETUP0				0x0000 +#define HSMC3_PULSE0				0x0004 +#define HSMC3_CYCLE0				0x0008 +#define HSMC3_MODE0				0x000c +#define HSMC3_SETUP1				0x0010 +#define HSMC3_PULSE1				0x0014 +#define HSMC3_CYCLE1				0x0018 +#define HSMC3_MODE1				0x001c +#define HSMC3_SETUP2				0x0020 +#define HSMC3_PULSE2				0x0024 +#define HSMC3_CYCLE2				0x0028 +#define HSMC3_MODE2				0x002c +#define HSMC3_SETUP3				0x0030 +#define HSMC3_PULSE3				0x0034 +#define HSMC3_CYCLE3				0x0038 +#define HSMC3_MODE3				0x003c +#define HSMC3_SETUP4				0x0040 +#define HSMC3_PULSE4				0x0044 +#define HSMC3_CYCLE4				0x0048 +#define HSMC3_MODE4				0x004c +#define HSMC3_SETUP5				0x0050 +#define HSMC3_PULSE5				0x0054 +#define HSMC3_CYCLE5				0x0058 +#define HSMC3_MODE5				0x005c + +/* Bitfields in SETUP0 */ +#define HSMC3_NWE_SETUP_OFFSET			0 +#define HSMC3_NWE_SETUP_SIZE			6 +#define HSMC3_NCS_WR_SETUP_OFFSET		8 +#define HSMC3_NCS_WR_SETUP_SIZE			6 +#define HSMC3_NRD_SETUP_OFFSET			16 +#define HSMC3_NRD_SETUP_SIZE			6 +#define HSMC3_NCS_RD_SETUP_OFFSET		24 +#define HSMC3_NCS_RD_SETUP_SIZE			6 + +/* Bitfields in PULSE0 */ +#define HSMC3_NWE_PULSE_OFFSET			0 +#define HSMC3_NWE_PULSE_SIZE			7 +#define HSMC3_NCS_WR_PULSE_OFFSET		8 +#define HSMC3_NCS_WR_PULSE_SIZE			7 +#define HSMC3_NRD_PULSE_OFFSET			16 +#define HSMC3_NRD_PULSE_SIZE			7 +#define HSMC3_NCS_RD_PULSE_OFFSET		24 +#define HSMC3_NCS_RD_PULSE_SIZE			7 + +/* Bitfields in CYCLE0 */ +#define HSMC3_NWE_CYCLE_OFFSET			0 +#define HSMC3_NWE_CYCLE_SIZE			9 +#define HSMC3_NRD_CYCLE_OFFSET			16 +#define HSMC3_NRD_CYCLE_SIZE			9 + +/* Bitfields in MODE0 */ +#define HSMC3_READ_MODE_OFFSET			0 +#define HSMC3_READ_MODE_SIZE			1 +#define HSMC3_WRITE_MODE_OFFSET			1 +#define HSMC3_WRITE_MODE_SIZE			1 +#define HSMC3_EXNW_MODE_OFFSET			4 +#define HSMC3_EXNW_MODE_SIZE			2 +#define HSMC3_BAT_OFFSET			8 +#define HSMC3_BAT_SIZE				1 +#define HSMC3_DBW_OFFSET			12 +#define HSMC3_DBW_SIZE				2 +#define HSMC3_TDF_CYCLES_OFFSET			16 +#define HSMC3_TDF_CYCLES_SIZE			4 +#define HSMC3_TDF_MODE_OFFSET			20 +#define HSMC3_TDF_MODE_SIZE			1 +#define HSMC3_PMEN_OFFSET			24 +#define HSMC3_PMEN_SIZE				1 +#define HSMC3_PS_OFFSET				28 +#define HSMC3_PS_SIZE				2 + +/* Bitfields in MODE1 */ +#define HSMC3_PD_OFFSET				28 +#define HSMC3_PD_SIZE				2 + +/* Constants for READ_MODE */ +#define HSMC3_READ_MODE_NCS_CONTROLLED		0 +#define HSMC3_READ_MODE_NRD_CONTROLLED		1 + +/* Constants for WRITE_MODE */ +#define HSMC3_WRITE_MODE_NCS_CONTROLLED		0 +#define HSMC3_WRITE_MODE_NWE_CONTROLLED		1 + +/* Constants for EXNW_MODE */ +#define HSMC3_EXNW_MODE_DISABLED		0 +#define HSMC3_EXNW_MODE_RESERVED		1 +#define HSMC3_EXNW_MODE_FROZEN			2 +#define HSMC3_EXNW_MODE_READY			3 + +/* Constants for BAT */ +#define HSMC3_BAT_BYTE_SELECT			0 +#define HSMC3_BAT_BYTE_WRITE			1 + +/* Constants for DBW */ +#define HSMC3_DBW_8_BITS			0 +#define HSMC3_DBW_16_BITS			1 +#define HSMC3_DBW_32_BITS			2 + +/* Bit manipulation macros */ +#define HSMC3_BIT(name)						\ +	(1 << HSMC3_##name##_OFFSET) +#define HSMC3_BF(name,value)					\ +	(((value) & ((1 << HSMC3_##name##_SIZE) - 1))		\ +	 << HSMC3_##name##_OFFSET) +#define HSMC3_BFEXT(name,value)					\ +	(((value) >> HSMC3_##name##_OFFSET)			\ +	 & ((1 << HSMC3_##name##_SIZE) - 1)) +#define HSMC3_BFINS(name,value,old)\ +	(((old) & ~(((1 << HSMC3_##name##_SIZE) - 1)		\ +		    << HSMC3_##name##_OFFSET))			\ +	 | HSMC3_BF(name,value)) + +/* Register access macros */ +#define hsmc3_readl(port,reg)					\ +	readl((port)->regs + HSMC3_##reg) +#define hsmc3_writel(port,reg,value)				\ +	writel((value), (port)->regs + HSMC3_##reg) + +#endif /* __CPU_AT32AP_HSMC3_H__ */ diff --git a/cpu/at32ap/interrupts.c b/cpu/at32ap/interrupts.c new file mode 100644 index 000000000..d720cfa94 --- /dev/null +++ b/cpu/at32ap/interrupts.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * 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/div64.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/sysreg.h> + +#include <asm/arch/platform.h> + +#define HANDLER_MASK	0x00ffffff +#define INTLEV_SHIFT	30 +#define INTLEV_MASK	0x00000003 + +DECLARE_GLOBAL_DATA_PTR; + +/* Incremented whenever COUNT reaches 0xffffffff by timer_interrupt_handler */ +volatile unsigned long timer_overflow; + +/* + * Instead of dividing by get_tbclk(), multiply by this constant and + * right-shift the result by 32 bits. + */ +static unsigned long tb_factor; + +static const struct device *intc_dev; + +unsigned long get_tbclk(void) +{ +	return gd->cpu_hz; +} + +unsigned long long get_ticks(void) +{ +	unsigned long lo, hi_now, hi_prev; + +	do { +		hi_prev = timer_overflow; +		lo = sysreg_read(COUNT); +		hi_now = timer_overflow; +	} while (hi_prev != hi_now); + +	return ((unsigned long long)hi_now << 32) | lo; +} + +void reset_timer(void) +{ +	sysreg_write(COUNT, 0); +	cpu_sync_pipeline();	/* process any pending interrupts */ +	timer_overflow = 0; +} + +unsigned long get_timer(unsigned long base) +{ +	u64 now = get_ticks(); + +	now *= tb_factor; +	return (unsigned long)(now >> 32) - base; +} + +void set_timer(unsigned long t) +{ +	unsigned long long ticks = t; +	unsigned long lo, hi, hi_new; + +	ticks = (ticks * get_tbclk()) / CFG_HZ; +	hi = ticks >> 32; +	lo = ticks & 0xffffffffUL; + +	do { +		timer_overflow = hi; +		sysreg_write(COUNT, lo); +		hi_new = timer_overflow; +	} while (hi_new != hi); +} + +/* + * For short delays only. It will overflow after a few seconds. + */ +void udelay(unsigned long usec) +{ +	unsigned long now, end; + +	now = sysreg_read(COUNT); + +	end = ((usec * (get_tbclk() / 10000)) + 50) / 100; +	end += now; + +	while (now > end) +		now = sysreg_read(COUNT); + +	while (now < end) +		now = sysreg_read(COUNT); +} + +static int set_interrupt_handler(unsigned int nr, void (*handler)(void), +				 unsigned int priority) +{ +	unsigned long intpr; +	unsigned long handler_addr = (unsigned long)handler; + +	if ((handler_addr & HANDLER_MASK) != handler_addr +	    || (priority & INTLEV_MASK) != priority) +		return -EINVAL; + +	intpr = (handler_addr & HANDLER_MASK); +	intpr |= (priority & INTLEV_MASK) << INTLEV_SHIFT; +	writel(intpr, intc_dev->regs + 4 * nr); + +	return 0; +} + +void timer_init(void) +{ +	extern void timer_interrupt_handler(void); +	u64 tmp; + +	sysreg_write(COUNT, 0); + +	tmp = (u64)CFG_HZ << 32; +	tmp += gd->cpu_hz / 2; +	do_div(tmp, gd->cpu_hz); +	tb_factor = (u32)tmp; + +	intc_dev = get_device(DEVICE_INTC); + +	if (!intc_dev +	    || set_interrupt_handler(0, &timer_interrupt_handler, 3)) +		return; + +	/* For all practical purposes, this gives us an overflow interrupt */ +	sysreg_write(COMPARE, 0xffffffff); +} diff --git a/cpu/at32ap/pio.c b/cpu/at32ap/pio.c new file mode 100644 index 000000000..8b6c3a35d --- /dev/null +++ b/cpu/at32ap/pio.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2006 Atmel Corporation + * + * 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/errno.h> +#include <asm/io.h> +#include <asm/arch/platform.h> + +#include "pio2.h" + +struct pio_state { +	const struct device *dev; +	u32 alloc_mask; +}; + +static struct pio_state pio_state[CFG_NR_PIOS]; + +int gpio_set_func(enum device_id gpio_devid, unsigned int start, +		  unsigned int nr_pins, enum gpio_func func) +{ +	const struct device *gpio; +	struct pio_state *state; +	u32 mask; + +	state = &pio_state[gpio_devid - DEVICE_PIOA]; + +	gpio = get_device(gpio_devid); +	if (!gpio) +		return -EBUSY; + +	state->dev = gpio; +	mask = ((1 << nr_pins) - 1) << start; + +	if (mask & state->alloc_mask) { +		put_device(gpio); +		return -EBUSY; +	} +	state->alloc_mask |= mask; + +	switch (func) { +	case GPIO_FUNC_GPIO: +		/* TODO */ +		return -EINVAL; +	case GPIO_FUNC_A: +		pio2_writel(gpio, ASR, mask); +		pio2_writel(gpio, PDR, mask); +		pio2_writel(gpio, PUDR, mask); +		break; +	case GPIO_FUNC_B: +		pio2_writel(gpio, BSR, mask); +		pio2_writel(gpio, PDR, mask); +		pio2_writel(gpio, PUDR, mask); +		break; +	} + +	return 0; +} + +void gpio_free(enum device_id gpio_devid, unsigned int start, +	       unsigned int nr_pins) +{ +	const struct device *gpio; +	struct pio_state *state; +	u32 mask; + +	state = &pio_state[gpio_devid - DEVICE_PIOA]; +	gpio = state->dev; +	mask = ((1 << nr_pins) - 1) << start; + +	pio2_writel(gpio, ODR, mask); +	pio2_writel(gpio, PER, mask); + +	state->alloc_mask &= ~mask; +	put_device(gpio); +} diff --git a/cpu/at32ap/pio2.h b/cpu/at32ap/pio2.h new file mode 100644 index 000000000..6b79de3c7 --- /dev/null +++ b/cpu/at32ap/pio2.h @@ -0,0 +1,44 @@ +/* + * Register definitions for Parallel Input/Output Controller + */ +#ifndef __CPU_AT32AP_PIO2_H__ +#define __CPU_AT32AP_PIO2_H__ + +/* PIO2 register offsets */ +#define PIO2_PER				0x0000 +#define PIO2_PDR				0x0004 +#define PIO2_PSR				0x0008 +#define PIO2_OER				0x0010 +#define PIO2_ODR				0x0014 +#define PIO2_OSR				0x0018 +#define PIO2_IFER				0x0020 +#define PIO2_IFDR				0x0024 +#define PIO2_ISFR				0x0028 +#define PIO2_SODR				0x0030 +#define PIO2_CODR				0x0034 +#define PIO2_ODSR				0x0038 +#define PIO2_PDSR				0x003c +#define PIO2_IER				0x0040 +#define PIO2_IDR				0x0044 +#define PIO2_IMR				0x0048 +#define PIO2_ISR				0x004c +#define PIO2_MDER				0x0050 +#define PIO2_MDDR				0x0054 +#define PIO2_MDSR				0x0058 +#define PIO2_PUDR				0x0060 +#define PIO2_PUER				0x0064 +#define PIO2_PUSR				0x0068 +#define PIO2_ASR				0x0070 +#define PIO2_BSR				0x0074 +#define PIO2_ABSR				0x0078 +#define PIO2_OWER				0x00a0 +#define PIO2_OWDR				0x00a4 +#define PIO2_OWSR				0x00a8 + +/* Register access macros */ +#define pio2_readl(port,reg)				\ +	readl((port)->regs + PIO2_##reg) +#define pio2_writel(port,reg,value)			\ +	writel((value), (port)->regs + PIO2_##reg) + +#endif /* __CPU_AT32AP_PIO2_H__ */ diff --git a/cpu/at32ap/pm.c b/cpu/at32ap/pm.c new file mode 100644 index 000000000..01ac325ee --- /dev/null +++ b/cpu/at32ap/pm.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2006 Atmel Corporation + * + * 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> + +#ifdef CFG_POWER_MANAGER +#include <asm/errno.h> +#include <asm/io.h> + +#include <asm/arch/memory-map.h> +#include <asm/arch/platform.h> + +#include "sm.h" + +/* Sanity checks */ +#if (CFG_CLKDIV_CPU > CFG_CLKDIV_HSB)		\ +	|| (CFG_CLKDIV_HSB > CFG_CLKDIV_PBA)	\ +	|| (CFG_CLKDIV_HSB > CFG_CLKDIV_PBB) +# error Constraint fCPU >= fHSB >= fPB{A,B} violated +#endif +#if defined(CONFIG_PLL) && ((CFG_PLL0_MUL < 1) || (CFG_PLL0_DIV < 1)) +# error Invalid PLL multiplier and/or divider +#endif + +DECLARE_GLOBAL_DATA_PTR; + +struct clock_domain_state { +	const struct device *bridge; +	unsigned long freq; +	u32 mask; +}; +static struct clock_domain_state ckd_state[NR_CLOCK_DOMAINS]; + +int pm_enable_clock(enum clock_domain_id id, unsigned int index) +{ +	const struct clock_domain *ckd = &chip_clock[id]; +	struct clock_domain_state *state = &ckd_state[id]; + +	if (ckd->bridge != NO_DEVICE) { +		state->bridge = get_device(ckd->bridge); +		if (!state->bridge) +			return -EBUSY; +	} + +	state->mask |= 1 << index; +	if (gd->sm) +		writel(state->mask, gd->sm->regs + ckd->reg); + +	return 0; +} + +void pm_disable_clock(enum clock_domain_id id, unsigned int index) +{ +	const struct clock_domain *ckd = &chip_clock[id]; +	struct clock_domain_state *state = &ckd_state[id]; + +	state->mask &= ~(1 << index); +	if (gd->sm) +		writel(state->mask, gd->sm->regs + ckd->reg); + +	if (ckd->bridge) +		put_device(state->bridge); +} + +unsigned long pm_get_clock_freq(enum clock_domain_id domain) +{ +	return ckd_state[domain].freq; +} + +void pm_init(void) +{ +	uint32_t cksel = 0; +	unsigned long main_clock; + +	/* Make sure we don't disable any device we're already using */ +	get_device(DEVICE_HRAMC); +	get_device(DEVICE_HEBI); + +	/* Enable the PICO as well */ +	ckd_state[CLOCK_CPU].mask |= 1; + +	gd->sm = get_device(DEVICE_SM); +	if (!gd->sm) +		panic("Unable to claim system manager device!\n"); + +	/* Disable any devices that haven't been explicitly claimed */ +	sm_writel(gd->sm, PM_PBB_MASK, ckd_state[CLOCK_PBB].mask); +	sm_writel(gd->sm, PM_PBA_MASK, ckd_state[CLOCK_PBA].mask); +	sm_writel(gd->sm, PM_HSB_MASK, ckd_state[CLOCK_HSB].mask); +	sm_writel(gd->sm, PM_CPU_MASK, ckd_state[CLOCK_CPU].mask); + +#ifdef CONFIG_PLL +	/* Initialize the PLL */ +	main_clock = (CFG_OSC0_HZ / CFG_PLL0_DIV) * CFG_PLL0_MUL; + +	sm_writel(gd->sm, PM_PLL0, (SM_BF(PLLCOUNT, CFG_PLL0_SUPPRESS_CYCLES) +				    | SM_BF(PLLMUL, CFG_PLL0_MUL - 1) +				    | SM_BF(PLLDIV, CFG_PLL0_DIV - 1) +				    | SM_BF(PLLOPT, CFG_PLL0_OPT) +				    | SM_BF(PLLOSC, 0) +				    | SM_BIT(PLLEN))); + +	/* Wait for lock */ +	while (!(sm_readl(gd->sm, PM_ISR) & SM_BIT(LOCK0))) ; +#else +	main_clock = CFG_OSC0_HZ; +#endif + +	/* Set up clocks for the CPU and all peripheral buses */ +	if (CFG_CLKDIV_CPU) { +		cksel |= SM_BIT(CPUDIV) | SM_BF(CPUSEL, CFG_CLKDIV_CPU - 1); +		ckd_state[CLOCK_CPU].freq = main_clock / (1 << CFG_CLKDIV_CPU); +	} else { +		ckd_state[CLOCK_CPU].freq = main_clock; +	} +	if (CFG_CLKDIV_HSB) { +		cksel |= SM_BIT(HSBDIV) | SM_BF(HSBSEL, CFG_CLKDIV_HSB - 1); +		ckd_state[CLOCK_HSB].freq = main_clock / (1 << CFG_CLKDIV_HSB); +	} else { +		ckd_state[CLOCK_HSB].freq = main_clock; +	} +	if (CFG_CLKDIV_PBA) { +		cksel |= SM_BIT(PBADIV) | SM_BF(PBASEL, CFG_CLKDIV_PBA - 1); +		ckd_state[CLOCK_PBA].freq = main_clock / (1 << CFG_CLKDIV_PBA); +	} else { +		ckd_state[CLOCK_PBA].freq = main_clock; +	} +	if (CFG_CLKDIV_PBB) { +		cksel |= SM_BIT(PBBDIV) | SM_BF(PBBSEL, CFG_CLKDIV_PBB - 1); +		ckd_state[CLOCK_PBB].freq = main_clock / (1 << CFG_CLKDIV_PBB); +	} else { +		ckd_state[CLOCK_PBB].freq = main_clock; +	} +	sm_writel(gd->sm, PM_CKSEL, cksel); + +	/* CFG_HZ currently depends on cpu_hz */ +	gd->cpu_hz = ckd_state[CLOCK_CPU].freq; + +#ifdef CONFIG_PLL +	/* Use PLL0 as main clock */ +	sm_writel(gd->sm, PM_MCCTRL, SM_BIT(PLLSEL)); +#endif +} + +#endif /* CFG_POWER_MANAGER */ diff --git a/cpu/at32ap/sm.h b/cpu/at32ap/sm.h new file mode 100644 index 000000000..ce81ef0a4 --- /dev/null +++ b/cpu/at32ap/sm.h @@ -0,0 +1,204 @@ +/* + * Register definitions for System Manager + */ +#ifndef __CPU_AT32AP_SM_H__ +#define __CPU_AT32AP_SM_H__ + +/* SM register offsets */ +#define SM_PM_MCCTRL				0x0000 +#define SM_PM_CKSEL				0x0004 +#define SM_PM_CPU_MASK				0x0008 +#define SM_PM_HSB_MASK				0x000c +#define SM_PM_PBA_MASK				0x0010 +#define SM_PM_PBB_MASK				0x0014 +#define SM_PM_PLL0				0x0020 +#define SM_PM_PLL1				0x0024 +#define SM_PM_VCTRL				0x0030 +#define SM_PM_VMREF				0x0034 +#define SM_PM_VMV				0x0038 +#define SM_PM_IER				0x0040 +#define SM_PM_IDR				0x0044 +#define SM_PM_IMR				0x0048 +#define SM_PM_ISR				0x004c +#define SM_PM_ICR				0x0050 +#define SM_PM_GCCTRL				0x0060 +#define SM_RTC_CTRL				0x0080 +#define SM_RTC_VAL				0x0084 +#define SM_RTC_TOP				0x0088 +#define SM_RTC_IER				0x0090 +#define SM_RTC_IDR				0x0094 +#define SM_RTC_IMR				0x0098 +#define SM_RTC_ISR				0x009c +#define SM_RTC_ICR				0x00a0 +#define SM_WDT_CTRL				0x00b0 +#define SM_WDT_CLR				0x00b4 +#define SM_WDT_EXT				0x00b8 +#define SM_RC_RCAUSE				0x00c0 +#define SM_EIM_IER				0x0100 +#define SM_EIM_IDR				0x0104 +#define SM_EIM_IMR				0x0108 +#define SM_EIM_ISR				0x010c +#define SM_EIM_ICR				0x0110 +#define SM_EIM_MODE				0x0114 +#define SM_EIM_EDGE				0x0118 +#define SM_EIM_LEVEL				0x011c +#define SM_EIM_TEST				0x0120 +#define SM_EIM_NMIC				0x0124 + +/* Bitfields in PM_CKSEL */ +#define SM_CPUSEL_OFFSET			0 +#define SM_CPUSEL_SIZE				3 +#define SM_CPUDIV_OFFSET			7 +#define SM_CPUDIV_SIZE				1 +#define SM_HSBSEL_OFFSET			8 +#define SM_HSBSEL_SIZE				3 +#define SM_HSBDIV_OFFSET			15 +#define SM_HSBDIV_SIZE				1 +#define SM_PBASEL_OFFSET			16 +#define SM_PBASEL_SIZE				3 +#define SM_PBADIV_OFFSET			23 +#define SM_PBADIV_SIZE				1 +#define SM_PBBSEL_OFFSET			24 +#define SM_PBBSEL_SIZE				3 +#define SM_PBBDIV_OFFSET			31 +#define SM_PBBDIV_SIZE				1 + +/* Bitfields in PM_PLL0 */ +#define SM_PLLEN_OFFSET				0 +#define SM_PLLEN_SIZE				1 +#define SM_PLLOSC_OFFSET			1 +#define SM_PLLOSC_SIZE				1 +#define SM_PLLOPT_OFFSET			2 +#define SM_PLLOPT_SIZE				3 +#define SM_PLLDIV_OFFSET			8 +#define SM_PLLDIV_SIZE				8 +#define SM_PLLMUL_OFFSET			16 +#define SM_PLLMUL_SIZE				8 +#define SM_PLLCOUNT_OFFSET			24 +#define SM_PLLCOUNT_SIZE			6 +#define SM_PLLTEST_OFFSET			31 +#define SM_PLLTEST_SIZE				1 + +/* Bitfields in PM_VCTRL */ +#define SM_VAUTO_OFFSET				0 +#define SM_VAUTO_SIZE				1 +#define SM_PM_VCTRL_VAL_OFFSET			8 +#define SM_PM_VCTRL_VAL_SIZE			7 + +/* Bitfields in PM_VMREF */ +#define SM_REFSEL_OFFSET			0 +#define SM_REFSEL_SIZE				4 + +/* Bitfields in PM_VMV */ +#define SM_PM_VMV_VAL_OFFSET			0 +#define SM_PM_VMV_VAL_SIZE			8 + +/* Bitfields in PM_ICR */ +#define SM_LOCK0_OFFSET				0 +#define SM_LOCK0_SIZE				1 +#define SM_LOCK1_OFFSET				1 +#define SM_LOCK1_SIZE				1 +#define SM_WAKE_OFFSET				2 +#define SM_WAKE_SIZE				1 +#define SM_VOK_OFFSET				3 +#define SM_VOK_SIZE				1 +#define SM_VMRDY_OFFSET				4 +#define SM_VMRDY_SIZE				1 +#define SM_CKRDY_OFFSET				5 +#define SM_CKRDY_SIZE				1 + +/* Bitfields in PM_GCCTRL */ +#define SM_OSCSEL_OFFSET			0 +#define SM_OSCSEL_SIZE				1 +#define SM_PLLSEL_OFFSET			1 +#define SM_PLLSEL_SIZE				1 +#define SM_CEN_OFFSET				2 +#define SM_CEN_SIZE				1 +#define SM_CPC_OFFSET				3 +#define SM_CPC_SIZE				1 +#define SM_DIVEN_OFFSET				4 +#define SM_DIVEN_SIZE				1 +#define SM_DIV_OFFSET				8 +#define SM_DIV_SIZE				8 + +/* Bitfields in RTC_CTRL */ +#define SM_PCLR_OFFSET				1 +#define SM_PCLR_SIZE				1 +#define SM_TOPEN_OFFSET				2 +#define SM_TOPEN_SIZE				1 +#define SM_CLKEN_OFFSET				3 +#define SM_CLKEN_SIZE				1 +#define SM_PSEL_OFFSET				8 +#define SM_PSEL_SIZE				16 + +/* Bitfields in RTC_VAL */ +#define SM_RTC_VAL_VAL_OFFSET			0 +#define SM_RTC_VAL_VAL_SIZE			31 + +/* Bitfields in RTC_TOP */ +#define SM_RTC_TOP_VAL_OFFSET			0 +#define SM_RTC_TOP_VAL_SIZE			32 + +/* Bitfields in RTC_ICR */ +#define SM_TOPI_OFFSET				0 +#define SM_TOPI_SIZE				1 + +/* Bitfields in WDT_CTRL */ +#define SM_KEY_OFFSET				24 +#define SM_KEY_SIZE				8 + +/* Bitfields in RC_RCAUSE */ +#define SM_POR_OFFSET				0 +#define SM_POR_SIZE				1 +#define SM_BOD_OFFSET				1 +#define SM_BOD_SIZE				1 +#define SM_EXT_OFFSET				2 +#define SM_EXT_SIZE				1 +#define SM_WDT_OFFSET				3 +#define SM_WDT_SIZE				1 +#define SM_NTAE_OFFSET				4 +#define SM_NTAE_SIZE				1 +#define SM_SERP_OFFSET				5 +#define SM_SERP_SIZE				1 + +/* Bitfields in EIM_EDGE */ +#define SM_INT0_OFFSET				0 +#define SM_INT0_SIZE				1 +#define SM_INT1_OFFSET				1 +#define SM_INT1_SIZE				1 +#define SM_INT2_OFFSET				2 +#define SM_INT2_SIZE				1 +#define SM_INT3_OFFSET				3 +#define SM_INT3_SIZE				1 + +/* Bitfields in EIM_LEVEL */ + +/* Bitfields in EIM_TEST */ +#define SM_TESTEN_OFFSET			31 +#define SM_TESTEN_SIZE				1 + +/* Bitfields in EIM_NMIC */ +#define SM_EN_OFFSET				0 +#define SM_EN_SIZE				1 + +/* Bit manipulation macros */ +#define SM_BIT(name)					\ +	(1 << SM_##name##_OFFSET) +#define SM_BF(name,value)				\ +	(((value) & ((1 << SM_##name##_SIZE) - 1))	\ +	 << SM_##name##_OFFSET) +#define SM_BFEXT(name,value)				\ +	(((value) >> SM_##name##_OFFSET)		\ +	 & ((1 << SM_##name##_SIZE) - 1)) +#define SM_BFINS(name,value,old)			\ +	(((old) & ~(((1 << SM_##name##_SIZE) - 1)	\ +		    << SM_##name##_OFFSET))		\ +	 | SM_BF(name,value)) + +/* Register access macros */ +#define sm_readl(port,reg)				\ +	readl((port)->regs + SM_##reg) +#define sm_writel(port,reg,value)			\ +	writel((value), (port)->regs + SM_##reg) + +#endif /* __CPU_AT32AP_SM_H__ */ diff --git a/cpu/at32ap/start.S b/cpu/at32ap/start.S new file mode 100644 index 000000000..79ee33b1f --- /dev/null +++ b/cpu/at32ap/start.S @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * 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 <asm/sysreg.h> + +#ifndef PART_SPECIFIC_BOOTSTRAP +# define PART_SPECIFIC_BOOTSTRAP +#endif + +#define SYSREG_MMUCR_I_OFFSET	2 +#define SYSREG_MMUCR_S_OFFSET	4 + +#define SR_INIT (SYSREG_BIT(GM) | SYSREG_BIT(EM) | SYSREG_BIT(M0)) +#define CPUCR_INIT (SYSREG_BIT(BI) | SYSREG_BIT(BE)		\ +		    | SYSREG_BIT(FE) | SYSREG_BIT(RE)		\ +		    | SYSREG_BIT(IBE) | SYSREG_BIT(IEE)) + +	.text +	.global	_start +_start: +	PART_SPECIFIC_BOOTSTRAP + +	/* Reset the Status Register */ +	mov	r0, lo(SR_INIT) +	orh	r0, hi(SR_INIT) +	mtsr	SYSREG_SR, r0 + +	/* Reset CPUCR and invalidate the BTB */ +	mov	r2, CPUCR_INIT +	mtsr	SYSREG_CPUCR, r2 + +	/* Flush the caches */ +	mov	r1, 0 +	cache	r1[4], 8 +	cache	r1[0], 0 +	sync	0 + +	/* Reset the MMU to default settings */ +	mov	r0, SYSREG_BIT(MMUCR_S) | SYSREG_BIT(MMUCR_I) +	mtsr	SYSREG_MMUCR, r0 + +	/* Internal RAM should not need any initialization.  We might +	   have to initialize external RAM here if the part doesn't +	   have internal RAM (or we may use the data cache) */ + +	/* Jump to cacheable segment */ +	lddpc	pc, 1f + +	.align	2 +1:	.long	2f + +2:	lddpc	sp, sp_init + +	/* +	 * Relocate the data section and initialize .bss.  Everything +	 * is guaranteed to be at least doubleword aligned by the +	 * linker script. +	 */ +	lddpc	r12, .Ldata_vma +	lddpc	r11, .Ldata_lma +	lddpc	r10, .Ldata_end +	sub	r10, r12 +4:	ld.d	r8, r11++ +	sub	r10, 8 +	st.d	r12++, r8 +	brne	4b + +	mov	r8, 0 +	mov	r9, 0 +	lddpc	r10, .Lbss_end +	sub	r10, r12 +4:	sub	r10, 8 +	st.d	r12++, r8 +	brne	4b + +	/* Initialize the GOT pointer */ +	lddpc	r6, got_init +3:	rsub	r6, pc +	ld.w	pc, r6[start_u_boot@got] + +	.align	2 +	.type	sp_init,@object +sp_init: +	.long	CFG_INIT_SP_ADDR +got_init: +	.long	3b - _GLOBAL_OFFSET_TABLE_ +.Ldata_lma: +	.long	__data_lma +.Ldata_vma: +	.long	_data +.Ldata_end: +	.long	_edata +.Lbss_end: +	.long	_end diff --git a/cpu/bf533/Makefile b/cpu/bf533/Makefile index a5c48dc04..9f4a0d801 100644 --- a/cpu/bf533/Makefile +++ b/cpu/bf533/Makefile @@ -38,7 +38,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/i386/Makefile b/cpu/i386/Makefile index cd46dea2c..50534b615 100644 --- a/cpu/i386/Makefile +++ b/cpu/i386/Makefile @@ -1,7 +1,7 @@  #  # (C) Copyright 2006  # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -#  +#  # (C) Copyright 2002  # Daniel Engström, Omicron Ceti AB, daniel@omicron.se.  # @@ -39,7 +39,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/ixp/Makefile b/cpu/ixp/Makefile index 28672705c..e1fb327bb 100644 --- a/cpu/ixp/Makefile +++ b/cpu/ixp/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/ixp/npe/Makefile b/cpu/ixp/npe/Makefile index 412b418b8..4de34fd5b 100644 --- a/cpu/ixp/npe/Makefile +++ b/cpu/ixp/npe/Makefile @@ -88,7 +88,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(LIB)  $(LIB):	$(obj).depend $(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/lh7a40x/Makefile b/cpu/lh7a40x/Makefile index 2fcafb043..bac2a640c 100644 --- a/cpu/lh7a40x/Makefile +++ b/cpu/lh7a40x/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/mcf52x2/Makefile b/cpu/mcf52x2/Makefile index a05a803cb..70d57cf60 100644 --- a/cpu/mcf52x2/Makefile +++ b/cpu/mcf52x2/Makefile @@ -37,7 +37,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/microblaze/Makefile b/cpu/microblaze/Makefile index 07ed6cedc..fd544254f 100644 --- a/cpu/microblaze/Makefile +++ b/cpu/microblaze/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/mips/Makefile b/cpu/mips/Makefile index f9a49df33..92dcc167e 100644 --- a/cpu/mips/Makefile +++ b/cpu/mips/Makefile @@ -37,7 +37,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/mpc5xx/Makefile b/cpu/mpc5xx/Makefile index d696e79a2..8aab0189d 100644 --- a/cpu/mpc5xx/Makefile +++ b/cpu/mpc5xx/Makefile @@ -47,7 +47,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/mpc5xxx/Makefile b/cpu/mpc5xxx/Makefile index 683ded8c9..235adb7c0 100644 --- a/cpu/mpc5xxx/Makefile +++ b/cpu/mpc5xxx/Makefile @@ -37,7 +37,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/mpc5xxx/fec.c b/cpu/mpc5xxx/fec.c index 19737ce86..37fe3e715 100644 --- a/cpu/mpc5xxx/fec.c +++ b/cpu/mpc5xxx/fec.c @@ -882,7 +882,7 @@ int mpc5xxx_fec_initialize(bd_t * bis)      defined(CONFIG_ICECUBE) || defined(CONFIG_INKA4X0)	|| \      defined(CONFIG_MCC200)  || defined(CONFIG_O2DNT)	|| \      defined(CONFIG_PM520)   || defined(CONFIG_TOP5200)	|| \ -    defined(CONFIG_TQM5200) +    defined(CONFIG_TQM5200) || defined(CONFIG_V38B)  # ifndef CONFIG_FEC_10MBIT  	fec->xcv_type = MII100;  # else diff --git a/cpu/mpc5xxx/interrupts.c b/cpu/mpc5xxx/interrupts.c index 7b5cb8be4..beeb22263 100644 --- a/cpu/mpc5xxx/interrupts.c +++ b/cpu/mpc5xxx/interrupts.c @@ -32,7 +32,7 @@   *   * Based on (well, mostly copied from) the code from the 2.4 kernel by   * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. - *  + *   * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>   * Copyright (C) 2003 Montavista Software, Inc   */ diff --git a/cpu/mpc8220/Makefile b/cpu/mpc8220/Makefile index 1f2e93176..b4fad286d 100644 --- a/cpu/mpc8220/Makefile +++ b/cpu/mpc8220/Makefile @@ -38,7 +38,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/mpc824x/Makefile b/cpu/mpc824x/Makefile index d9fd9bfdb..f249dd7c3 100644 --- a/cpu/mpc824x/Makefile +++ b/cpu/mpc824x/Makefile @@ -41,7 +41,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  $(obj)bedbug_603e.c:  	ln -s $(src)../mpc8260/bedbug_603e.c $(obj)bedbug_603e.c diff --git a/cpu/mpc8260/Makefile b/cpu/mpc8260/Makefile index b1f1c1899..80d785229 100644 --- a/cpu/mpc8260/Makefile +++ b/cpu/mpc8260/Makefile @@ -37,7 +37,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) $(obj)kgdb.o +	$(AR) $(ARFLAGS) $@ $(OBJS) $(obj)kgdb.o  ######################################################################### diff --git a/cpu/mpc83xx/Makefile b/cpu/mpc83xx/Makefile index f3fa6fd93..b2a6b3e9c 100644 --- a/cpu/mpc83xx/Makefile +++ b/cpu/mpc83xx/Makefile @@ -1,7 +1,7 @@  #  # (C) Copyright 2006  # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -#  +#  # Copyright 2004 Freescale Semiconductor, Inc.  #  # See file CREDITS for list of people who contributed to this @@ -38,7 +38,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/mpc85xx/Makefile b/cpu/mpc85xx/Makefile index bbc50844e..ff67dcdd3 100644 --- a/cpu/mpc85xx/Makefile +++ b/cpu/mpc85xx/Makefile @@ -30,7 +30,7 @@ LIB	= $(obj)lib$(CPU).a  START	= start.o resetvec.o  COBJS	= traps.o cpu.o cpu_init.o speed.o interrupts.o \ -	  pci.o serial_scc.o commproc.o ether_fcc.o i2c.o spd_sdram.o +	  pci.o serial_scc.o commproc.o ether_fcc.o spd_sdram.o  SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) @@ -39,7 +39,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/mpc85xx/cpu.c b/cpu/mpc85xx/cpu.c index f7fe22e3e..0507c47e6 100644 --- a/cpu/mpc85xx/cpu.c +++ b/cpu/mpc85xx/cpu.c @@ -30,7 +30,10 @@  #include <command.h>  #include <asm/cache.h> -/* ------------------------------------------------------------------------- */ +#if defined(CONFIG_OF_FLAT_TREE) +#include <ft_build.h> +#endif +  int checkcpu (void)  { @@ -227,3 +230,48 @@ int dma_xfer(void *dest, uint count, void *src) {  	return dma_check();  }  #endif + + +#ifdef CONFIG_OF_FLAT_TREE +void +ft_cpu_setup(void *blob, bd_t *bd) +{ +	u32 *p; +	ulong clock; +	int len; + +	clock = bd->bi_busfreq; +	p = ft_get_prop(blob, "/cpus/" OF_CPU "/bus-frequency", &len); +	if (p != NULL) +		*p = cpu_to_be32(clock); + +	p = ft_get_prop(blob, "/" OF_SOC "/serial@4500/clock-frequency", &len); +	if (p != NULL) +		*p = cpu_to_be32(clock); + +	p = ft_get_prop(blob, "/" OF_SOC "/serial@4600/clock-frequency", &len); +	if (p != NULL) +		*p = cpu_to_be32(clock); + +#if defined(CONFIG_MPC85XX_TSEC1) +	p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/mac-address", &len); +		memcpy(p, bd->bi_enetaddr, 6); +#endif + +#if defined(CONFIG_HAS_ETH1) +	p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/mac-address", &len); +		memcpy(p, bd->bi_enet1addr, 6); +#endif + +#if defined(CONFIG_HAS_ETH2) +	p = ft_get_prop(blob, "/" OF_SOC "/ethernet@26000/mac-address", &len); +		memcpy(p, bd->bi_enet2addr, 6); +#endif + +#if defined(CONFIG_HAS_ETH3) +	p = ft_get_prop(blob, "/" OF_SOC "/ethernet@27000/mac-address", &len); +		memcpy(p, bd->bi_enet3addr, 6); +#endif + +} +#endif diff --git a/cpu/mpc85xx/cpu_init.c b/cpu/mpc85xx/cpu_init.c index c12b47b58..9f4d36c1a 100644 --- a/cpu/mpc85xx/cpu_init.c +++ b/cpu/mpc85xx/cpu_init.c @@ -32,6 +32,7 @@  DECLARE_GLOBAL_DATA_PTR; +  #ifdef CONFIG_CPM2  static void config_8560_ioports (volatile immap_t * immr)  { diff --git a/cpu/mpc85xx/i2c.c b/cpu/mpc85xx/i2c.c deleted file mode 100644 index 32dcf5d47..000000000 --- a/cpu/mpc85xx/i2c.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * (C) Copyright 2003,Motorola Inc. - * Xianghua Xiao <x.xiao@motorola.com> - * Adapted for Motorola 85xx chip. - * - * (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> -#include <command.h> -#include <asm/io.h> - -#ifdef CONFIG_HARD_I2C -#include <i2c.h> - -#define TIMEOUT (CFG_HZ/4) - -#define I2C_Addr ((u8 *)(CFG_CCSRBAR + 0x3000)) - -#define I2CADR  &I2C_Addr[0] -#define I2CFDR  &I2C_Addr[4] -#define I2CCCR  &I2C_Addr[8] -#define I2CCSR  &I2C_Addr[12] -#define I2CCDR  &I2C_Addr[16] -#define I2CDFSRR &I2C_Addr[20] - -#define I2C_READ  1 -#define I2C_WRITE 0 - -void -i2c_init(int speed, int slaveadd) -{ -	/* stop I2C controller */ -	writeb(0x0, I2CCCR); - -	/* set clock */ -	writeb(0x3f, I2CFDR); - -	/* set default filter */ -	writeb(0x10,I2CDFSRR); - -	/* write slave address */ -	writeb(slaveadd, I2CADR); - -	/* clear status register */ -	writeb(0x0, I2CCSR); - -	/* start I2C controller */ -	writeb(MPC85xx_I2CCR_MEN, I2CCCR); -} - -static __inline__ int -i2c_wait4bus (void) -{ -	ulong timeval = get_timer (0); - -	while (readb(I2CCSR) & MPC85xx_I2CSR_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 = readb(I2CCSR); - -		if (!(csr & MPC85xx_I2CSR_MIF)) -			continue; - -		writeb(0x0, I2CCSR); - -		if (csr & MPC85xx_I2CSR_MAL) { -			debug("i2c_wait: MAL\n"); -			return -1; -		} - -		if (!(csr & MPC85xx_I2CSR_MCF))	{ -			debug("i2c_wait: unfinished\n"); -			return -1; -		} - -		if (write == I2C_WRITE && (csr & MPC85xx_I2CSR_RXAK)) { -			debug("i2c_wait: No RXACK\n"); -			return -1; -		} - -		return 0; -	} while (get_timer (timeval) < TIMEOUT); - -	debug("i2c_wait: timed out\n"); -	return -1; -} - -static __inline__ int -i2c_write_addr (u8 dev, u8 dir, int rsta) -{ -	writeb(MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | MPC85xx_I2CCR_MTX | -	       (rsta?MPC85xx_I2CCR_RSTA:0), -	       I2CCCR); - -	writeb((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; - -	writeb(MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | MPC85xx_I2CCR_MTX, -	       I2CCCR); - -	for (i=0; i < length; i++) { -		writeb(data[i], I2CCDR); - -		if (i2c_wait (I2C_WRITE) < 0) -			break; -	} - -	return i; -} - -static __inline__ int -__i2c_read (u8 *data, int length) -{ -	int i; - -	writeb(MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | -	       ((length == 1) ? MPC85xx_I2CCR_TXAK : 0), -	       I2CCCR); - -	/* dummy read */ -	readb(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) -			writeb(MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | -			       MPC85xx_I2CCR_TXAK, -			       I2CCCR); - -		/* Generate stop on last byte */ -		if (i == length - 1) -			writeb(MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_TXAK, I2CCCR); - -		data[i] = readb(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: -	writeb(MPC85xx_I2CCR_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: -	writeb(MPC85xx_I2CCR_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); -} - -uchar i2c_reg_read (uchar i2c_addr, uchar reg) -{ -	uchar buf[1]; - -	i2c_read (i2c_addr, reg, 1, buf, 1); - -	return (buf[0]); -} - -void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val) -{ -	i2c_write (i2c_addr, reg, 1, &val, 1); -} - -#endif /* CONFIG_HARD_I2C */ diff --git a/cpu/mpc85xx/pci.c b/cpu/mpc85xx/pci.c index a94493e08..84f839ae1 100644 --- a/cpu/mpc85xx/pci.c +++ b/cpu/mpc85xx/pci.c @@ -29,69 +29,101 @@  #include <asm/cpm_85xx.h>  #include <pci.h> +#if defined(CONFIG_OF_FLAT_TREE) +#include <ft_build.h> +#endif  #if defined(CONFIG_PCI) +static struct pci_controller *pci_hose; +  void -pci_mpc85xx_init(struct pci_controller *hose) +pci_mpc85xx_init(struct pci_controller *board_hose)  { +	u16 reg16; +	u32 dev; +  	volatile immap_t    *immap = (immap_t *)CFG_CCSRBAR;  	volatile ccsr_pcix_t *pcix = &immap->im_pcix; +#ifdef CONFIG_MPC85XX_PCI2 +	volatile ccsr_pcix_t *pcix2 = &immap->im_pcix2; +#endif +	volatile ccsr_gur_t *gur = &immap->im_gur; +	struct pci_controller * hose; -	u16 reg16; +	pci_hose = board_hose; + +	hose = &pci_hose[0];  	hose->first_busno = 0;  	hose->last_busno = 0xff; -	pci_set_region(hose->regions + 0, -		       CFG_PCI1_MEM_BASE, -		       CFG_PCI1_MEM_PHYS, -		       CFG_PCI1_MEM_SIZE, -		       PCI_REGION_MEM); - -	pci_set_region(hose->regions + 1, -		       CFG_PCI1_IO_BASE, -		       CFG_PCI1_IO_PHYS, -		       CFG_PCI1_IO_SIZE, -		       PCI_REGION_IO); - -	hose->region_count = 2; -  	pci_setup_indirect(hose,  			   (CFG_IMMR+0x8000),  			   (CFG_IMMR+0x8004)); +	/* +	 * Hose scan. +	 */ +	dev = PCI_BDF(hose->first_busno, 0, 0); +	pci_hose_read_config_word (hose, dev, PCI_COMMAND, ®16); +	reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; +	pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16); + +	/* +	 * Clear non-reserved bits in status register. +	 */ +	pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff); + +	if (!(gur->pordevsr & PORDEVSR_PCI)) { +		/* PCI-X init */ +		if (CONFIG_SYS_CLK_FREQ < 66000000) +			printf("PCI-X will only work at 66 MHz\n"); + +		reg16 = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ +			| PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E; +		pci_hose_write_config_word(hose, dev, PCIX_COMMAND, reg16); +	} +  	pcix->potar1   = (CFG_PCI1_MEM_BASE >> 12) & 0x000fffff;  	pcix->potear1  = 0x00000000; -	pcix->powbar1  = (CFG_PCI1_MEM_BASE >> 12) & 0x000fffff; +	pcix->powbar1  = (CFG_PCI1_MEM_PHYS >> 12) & 0x000fffff;  	pcix->powbear1 = 0x00000000; -	pcix->powar1   = 0x8004401c;	/* 512M MEM space */ +	pcix->powar1 = (POWAR_EN | POWAR_MEM_READ | +			POWAR_MEM_WRITE | POWAR_MEM_512M); -	pcix->potar2   = 0x00000000; +	pcix->potar2  = (CFG_PCI1_IO_BASE >> 12) & 0x000fffff;  	pcix->potear2  = 0x00000000; -	pcix->powbar2  = (CFG_PCI1_IO_BASE >> 12) & 0x000fffff; +	pcix->powbar2  = (CFG_PCI1_IO_PHYS >> 12) & 0x000fffff;  	pcix->powbear2 = 0x00000000; -	pcix->powar2   = 0x80088017;	/* 16M IO space */ +	pcix->powar2 = (POWAR_EN | POWAR_IO_READ | +			POWAR_IO_WRITE | POWAR_IO_1M);  	pcix->pitar1 = 0x00000000;  	pcix->piwbar1 = 0x00000000; -	pcix->piwar1 = 0xa0f5501e;	/* Enable, Prefetch, Local Mem, -					 * Snoop R/W, 2G */ +	pcix->piwar1 = (PIWAR_EN | PIWAR_PF | PIWAR_LOCAL | +			PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_MEM_2G); -	/* -	 * Hose scan. -	 */ -	pci_register_hose(hose); +	pcix->powar3 = 0; +	pcix->powar4 = 0; +	pcix->piwar2 = 0; +	pcix->piwar3 = 0; -	pci_read_config_word (PCI_BDF(0,0,0), PCI_COMMAND, ®16); -	reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; -	pci_write_config_word(PCI_BDF(0,0,0), PCI_COMMAND, reg16); +	pci_set_region(hose->regions + 0, +		       CFG_PCI1_MEM_BASE, +		       CFG_PCI1_MEM_PHYS, +		       CFG_PCI1_MEM_SIZE, +		       PCI_REGION_MEM); -	/* -	 * Clear non-reserved bits in status register. -	 */ -	pci_write_config_word(PCI_BDF(0,0,0), PCI_STATUS, 0xffff); -	pci_write_config_byte(PCI_BDF(0,0,0), PCI_LATENCY_TIMER,0x80); +	pci_set_region(hose->regions + 1, +		       CFG_PCI1_IO_BASE, +		       CFG_PCI1_IO_PHYS, +		       CFG_PCI1_IO_SIZE, +		       PCI_REGION_IO); + +	hose->region_count = 2; + +	pci_register_hose(hose);  #if defined(CONFIG_MPC8555CDS) || defined(CONFIG_MPC8541CDS)  	/* @@ -117,6 +149,94 @@ pci_mpc85xx_init(struct pci_controller *hose)  #endif  	hose->last_busno = pci_hose_scan(hose); + +#ifdef CONFIG_MPC85XX_PCI2 +	hose = &pci_hose[1]; + +	hose->first_busno = pci_hose[0].last_busno + 1; +	hose->last_busno = 0xff; + +	pci_setup_indirect(hose, +			   (CFG_IMMR+0x9000), +			   (CFG_IMMR+0x9004)); + +	dev = PCI_BDF(hose->first_busno, 0, 0); +	pci_hose_read_config_word (hose, dev, PCI_COMMAND, ®16); +	reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; +	pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16); + +	/* +	 * Clear non-reserved bits in status register. +	 */ +	pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff); + +	pcix2->potar1   = (CFG_PCI2_MEM_BASE >> 12) & 0x000fffff; +	pcix2->potear1  = 0x00000000; +	pcix2->powbar1  = (CFG_PCI2_MEM_PHYS >> 12) & 0x000fffff; +	pcix2->powbear1 = 0x00000000; +	pcix2->powar1 = (POWAR_EN | POWAR_MEM_READ | +			POWAR_MEM_WRITE | POWAR_MEM_512M); + +	pcix2->potar2  = (CFG_PCI2_IO_BASE >> 12) & 0x000fffff; +	pcix2->potear2  = 0x00000000; +	pcix2->powbar2  = (CFG_PCI2_IO_PHYS >> 12) & 0x000fffff; +	pcix2->powbear2 = 0x00000000; +	pcix2->powar2 = (POWAR_EN | POWAR_IO_READ | +			POWAR_IO_WRITE | POWAR_IO_1M); + +	pcix2->pitar1 = 0x00000000; +	pcix2->piwbar1 = 0x00000000; +	pcix2->piwar1 = (PIWAR_EN | PIWAR_PF | PIWAR_LOCAL | +			PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_MEM_2G); + +	pcix2->powar3 = 0; +	pcix2->powar4 = 0; +	pcix2->piwar2 = 0; +	pcix2->piwar3 = 0; + +	pci_set_region(hose->regions + 0, +		       CFG_PCI2_MEM_BASE, +		       CFG_PCI2_MEM_PHYS, +		       CFG_PCI2_MEM_SIZE, +		       PCI_REGION_MEM); + +	pci_set_region(hose->regions + 1, +		       CFG_PCI2_IO_BASE, +		       CFG_PCI2_IO_PHYS, +		       CFG_PCI2_IO_SIZE, +		       PCI_REGION_IO); + +	hose->region_count = 2; + +	/* +	 * Hose scan. +	 */ +	pci_register_hose(hose); + +	hose->last_busno = pci_hose_scan(hose); +#endif  } +#ifdef CONFIG_OF_FLAT_TREE +void +ft_pci_setup(void *blob, bd_t *bd) +{ +	u32 *p; +	int len; + +	p = (u32 *)ft_get_prop(blob, "/" OF_SOC "/pci@8000/bus-range", &len); +	if (p != NULL) { +		p[0] = pci_hose[0].first_busno; +		p[1] = pci_hose[0].last_busno; +	} + +#ifdef CONFIG_MPC85XX_PCI2 +	p = (u32 *)ft_get_prop(blob, "/" OF_SOC "/pci@9000/bus-range", &len); +	if (p != NULL) { +		p[0] = pci_hose[1].first_busno; +		p[1] = pci_hose[1].last_busno; +	} +#endif +} +#endif /* CONFIG_OF_FLAT_TREE */  #endif /* CONFIG_PCI */ diff --git a/cpu/mpc85xx/spd_sdram.c b/cpu/mpc85xx/spd_sdram.c index af99282dd..6da5367a7 100644 --- a/cpu/mpc85xx/spd_sdram.c +++ b/cpu/mpc85xx/spd_sdram.c @@ -131,8 +131,8 @@ convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)  		800,  		900,  		250, -		330,	/* FIXME: Is 333 better/valid? */ -		660,	/* FIXME: Is 667 better/valid? */ +		330, +		660,  		750,  		0,	/* undefined */  		0	/* undefined */ @@ -146,6 +146,28 @@ convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)  } +/* + * Determine Refresh Rate.  Ignore self refresh bit on DDR I. + * Table from SPD Spec, Byte 12, converted to picoseconds and + * filled in with "default" normal values. + */ +unsigned int determine_refresh_rate(unsigned int spd_refresh) +{ +	unsigned int refresh_time_ns[8] = { +		15625000,	/* 0 Normal    1.00x */ +		3900000,	/* 1 Reduced    .25x */ +		7800000,	/* 2 Extended   .50x */ +		31300000,	/* 3 Extended  2.00x */ +		62500000,	/* 4 Extended  4.00x */ +		125000000,	/* 5 Extended  8.00x */ +		15625000,	/* 6 Normal    1.00x  filler */ +		15625000,	/* 7 Normal    1.00x  filler */ +	}; + +	return picos_to_clk(refresh_time_ns[spd_refresh & 0x7]); +} + +  long int  spd_sdram(void)  { @@ -157,6 +179,10 @@ spd_sdram(void)  	unsigned int rank_density;  	unsigned int odt_rd_cfg, odt_wr_cfg;  	unsigned int odt_cfg, mode_odt_enable; +	unsigned int refresh_clk; +#ifdef MPC85xx_DDR_SDRAM_CLK_CNTL +	unsigned char clk_adjust; +#endif  	unsigned int dqs_cfg;  	unsigned char twr_clk, twtr_clk, twr_auto_clk;  	unsigned int tCKmin_ps, tCKmax_ps; @@ -740,38 +766,21 @@ spd_sdram(void)  	ddr->sdram_mode_2 = 0;  	debug("DDR: sdram_mode_2 = 0x%08x\n", ddr->sdram_mode_2); -  	/* -	 * Determine Refresh Rate.  Ignore self refresh bit on DDR I. -	 * Table from SPD Spec, Byte 12, converted to picoseconds and -	 * filled in with "default" normal values. +	 * Determine Refresh Rate.  	 */ -	{ -		unsigned int refresh_clk; -		unsigned int refresh_time_ns[8] = { -			15625000,	/* 0 Normal    1.00x */ -			3900000,	/* 1 Reduced    .25x */ -			7800000,	/* 2 Extended   .50x */ -			31300000,	/* 3 Extended  2.00x */ -			62500000,	/* 4 Extended  4.00x */ -			125000000,	/* 5 Extended  8.00x */ -			15625000,	/* 6 Normal    1.00x  filler */ -			15625000,	/* 7 Normal    1.00x  filler */ -		}; - -		refresh_clk = picos_to_clk(refresh_time_ns[spd.refresh & 0x7]); +	refresh_clk = determine_refresh_rate(spd.refresh & 0x7); -		/* -		 * Set BSTOPRE to 0x100 for page mode -		 * If auto-charge is used, set BSTOPRE = 0 -		 */ -		ddr->sdram_interval = -			(0 -			 | (refresh_clk & 0x3fff) << 16 -			 | 0x100 -			 ); -		debug("DDR: sdram_interval = 0x%08x\n", ddr->sdram_interval); -	} +	/* +	 * Set BSTOPRE to 0x100 for page mode +	 * If auto-charge is used, set BSTOPRE = 0 +	 */ +	ddr->sdram_interval = +	    (0 +	     | (refresh_clk & 0x3fff) << 16 +	     | 0x100 +	     ); +	debug("DDR: sdram_interval = 0x%08x\n", ddr->sdram_interval);  	/*  	 * Is this an ECC DDR chip? @@ -835,28 +844,23 @@ spd_sdram(void)  #ifdef MPC85xx_DDR_SDRAM_CLK_CNTL -	{ -		unsigned char clk_adjust; - -		/* -		 * Setup the clock control. -		 * SDRAM_CLK_CNTL[0] = Source synchronous enable == 1 -		 * SDRAM_CLK_CNTL[5-7] = Clock Adjust -		 *	0110	3/4 cycle late -		 *	0111	7/8 cycle late -		 */ -		if (spd.mem_type == SPD_MEMTYPE_DDR) { -			clk_adjust = 0x6; -		} else { -			clk_adjust = 0x7; -		} +	/* +	 * Setup the clock control. +	 * SDRAM_CLK_CNTL[0] = Source synchronous enable == 1 +	 * SDRAM_CLK_CNTL[5-7] = Clock Adjust +	 *	0110	3/4 cycle late +	 *	0111	7/8 cycle late +	 */ +	if (spd.mem_type == SPD_MEMTYPE_DDR) +		clk_adjust = 0x6; +	else +		clk_adjust = 0x7; -		ddr->sdram_clk_cntl = (0 +	ddr->sdram_clk_cntl = (0  			       | 0x80000000  			       | (clk_adjust << 23)  			       ); -		debug("DDR: sdram_clk_cntl = 0x%08x\n", ddr->sdram_clk_cntl); -	} +	debug("DDR: sdram_clk_cntl = 0x%08x\n", ddr->sdram_clk_cntl);  #endif  	/* @@ -1081,26 +1085,16 @@ ddr_enable_ecc(unsigned int dram_size)  		}  	} -	/* 8K */ -	dma_xfer((uint *)0x2000, 0x2000, (uint *)0); -	/* 16K */ -	dma_xfer((uint *)0x4000, 0x4000, (uint *)0); -	/* 32K */ -	dma_xfer((uint *)0x8000, 0x8000, (uint *)0); -	/* 64K */ -	dma_xfer((uint *)0x10000, 0x10000, (uint *)0); -	/* 128k */ -	dma_xfer((uint *)0x20000, 0x20000, (uint *)0); -	/* 256k */ -	dma_xfer((uint *)0x40000, 0x40000, (uint *)0); -	/* 512k */ -	dma_xfer((uint *)0x80000, 0x80000, (uint *)0); -	/* 1M */ -	dma_xfer((uint *)0x100000, 0x100000, (uint *)0); -	/* 2M */ -	dma_xfer((uint *)0x200000, 0x200000, (uint *)0); -	/* 4M */ -	dma_xfer((uint *)0x400000, 0x400000, (uint *)0); +	dma_xfer((uint *)0x002000, 0x002000, (uint *)0); /* 8K */ +	dma_xfer((uint *)0x004000, 0x004000, (uint *)0); /* 16K */ +	dma_xfer((uint *)0x008000, 0x008000, (uint *)0); /* 32K */ +	dma_xfer((uint *)0x010000, 0x010000, (uint *)0); /* 64K */ +	dma_xfer((uint *)0x020000, 0x020000, (uint *)0); /* 128k */ +	dma_xfer((uint *)0x040000, 0x040000, (uint *)0); /* 256k */ +	dma_xfer((uint *)0x080000, 0x080000, (uint *)0); /* 512k */ +	dma_xfer((uint *)0x100000, 0x100000, (uint *)0); /* 1M */ +	dma_xfer((uint *)0x200000, 0x200000, (uint *)0); /* 2M */ +	dma_xfer((uint *)0x400000, 0x400000, (uint *)0); /* 4M */  	for (i = 1; i < dram_size / 0x800000; i++) {  		dma_xfer((uint *)(0x800000*i), 0x800000, (uint *)0); diff --git a/cpu/mpc86xx/Makefile b/cpu/mpc86xx/Makefile new file mode 100644 index 000000000..fffcfd240 --- /dev/null +++ b/cpu/mpc86xx/Makefile @@ -0,0 +1,51 @@ +# +# (C) Copyright 2002,2003 Motorola Inc. +# Xianghua Xiao,X.Xiao@motorola.com +# +# (C) Copyright 2004 Freescale Semiconductor. (MC86xx Port) +# Jeff Brown +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB	= $(obj)lib$(CPU).a + +START	= start.o #resetvec.o +SOBJS	= cache.o +COBJS	= traps.o cpu.o cpu_init.o speed.o interrupts.o \ +	  pci.o pcie_indirect.o spd_sdram.o + +SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) +START	:= $(addprefix $(obj),$(START)) + +all:	$(obj).depend $(START) $(LIB) + +$(LIB):	$(OBJS) +	$(AR) $(ARFLAGS) $@ $(ASOBJS) $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/mpc86xx/cache.S b/cpu/mpc86xx/cache.S new file mode 100644 index 000000000..f316b3ec1 --- /dev/null +++ b/cpu/mpc86xx/cache.S @@ -0,0 +1,374 @@ +#include <config.h> +#include <mpc86xx.h> +#include <version.h> + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +#include <asm/cache.h> +#include <asm/mmu.h> + +#ifndef CACHE_LINE_SIZE +# define CACHE_LINE_SIZE L1_CACHE_BYTES +#endif + +#if CACHE_LINE_SIZE == 128 +#define LG_CACHE_LINE_SIZE 7 +#elif CACHE_LINE_SIZE == 32 +#define LG_CACHE_LINE_SIZE 5 +#elif CACHE_LINE_SIZE == 16 +#define LG_CACHE_LINE_SIZE 4 +#elif CACHE_LINE_SIZE == 8 +#define LG_CACHE_LINE_SIZE 3 +#else +# error "Invalid cache line size!" +#endif + +/* + * Most of this code is taken from 74xx_7xx/cache.S + * and then cleaned up a bit + */ + +/* + * Invalidate L1 instruction cache. + */ +_GLOBAL(invalidate_l1_instruction_cache) +	/* use invalidate-all bit in HID0 */ +	mfspr	r3,HID0 +	ori	r3,r3,HID0_ICFI +	mtspr	HID0,r3 +	isync +	blr + +/* + * Invalidate L1 data cache. + */ +_GLOBAL(invalidate_l1_data_cache) +	mfspr	r3,HID0 +	ori	r3,r3,HID0_DCFI +	mtspr	HID0,r3 +	isync +	blr + +/* + * Flush data cache. + */ +_GLOBAL(flush_data_cache) +	lis	r3,0 +	lis	r5,CACHE_LINE_SIZE +flush: +	cmp	0,1,r3,r5 +	bge	done +	lwz	r5,0(r3) +	lis	r5,CACHE_LINE_SIZE +	addi	r3,r3,0x4 +	b	flush +done: +	blr +/* + * Write any modified data cache blocks out to memory + * and invalidate the corresponding instruction cache blocks. + * This is a no-op on the 601. + * + * flush_icache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_icache_range) +	li	r5,CACHE_LINE_SIZE-1 +	andc	r3,r3,r5 +	subf	r4,r3,r4 +	add	r4,r4,r5 +	srwi.	r4,r4,LG_CACHE_LINE_SIZE +	beqlr +	mtctr	r4 +	mr	r6,r3 +1:	dcbst	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	sync				/* wait for dcbst's to get to ram */ +	mtctr	r4 +2:	icbi	0,r6 +	addi	r6,r6,CACHE_LINE_SIZE +	bdnz	2b +	sync				/* additional sync needed on g4 */ +	isync +	blr +/* + * Write any modified data cache blocks out to memory. + * Does not invalidate the corresponding cache lines (especially for + * any corresponding instruction cache). + * + * clean_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(clean_dcache_range) +	li	r5,CACHE_LINE_SIZE-1 +	andc	r3,r3,r5	/* align r3 down to cache line */ +	subf	r4,r3,r4	/* r4 = offset of stop from start of cache line */ +	add	r4,r4,r5	/* r4 += cache_line_size-1 */ +	srwi.	r4,r4,LG_CACHE_LINE_SIZE  /* r4 = number of cache lines to flush */ +	beqlr				  /* if r4 == 0 return */ +	mtctr	r4			  /* ctr = r4 */ + +	sync +1:	dcbst	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	sync				/* wait for dcbst's to get to ram */ +	blr + +/* + * Write any modified data cache blocks out to memory + * and invalidate the corresponding instruction cache blocks. + * + * flush_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_dcache_range) +	li	r5,CACHE_LINE_SIZE-1 +	andc	r3,r3,r5 +	subf	r4,r3,r4 +	add	r4,r4,r5 +	srwi.	r4,r4,LG_CACHE_LINE_SIZE +	beqlr +	mtctr	r4 + +	sync +1:	dcbf	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	sync				/* wait for dcbf's to get to ram */ +	blr + +/* + * Like above, but invalidate the D-cache.  This is used by the 8xx + * to invalidate the cache so the PPC core doesn't get stale data + * from the CPM (no cache snooping here :-). + * + * invalidate_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(invalidate_dcache_range) +	li	r5,CACHE_LINE_SIZE-1 +	andc	r3,r3,r5 +	subf	r4,r3,r4 +	add	r4,r4,r5 +	srwi.	r4,r4,LG_CACHE_LINE_SIZE +	beqlr +	mtctr	r4 + +	sync +1:	dcbi	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	sync				/* wait for dcbi's to get to ram */ +	blr + +/* + * Flush a particular page from the data cache to RAM. + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * + *	void __flush_page_to_ram(void *page) + */ +_GLOBAL(__flush_page_to_ram) +	rlwinm	r3,r3,0,0,19		/* Get page base address */ +	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */ +	mtctr	r4 +	mr	r6,r3 +0:	dcbst	0,r3			/* Write line to ram */ +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	0b +	sync +	mtctr	r4 +1:	icbi	0,r6 +	addi	r6,r6,CACHE_LINE_SIZE +	bdnz	1b +	sync +	isync +	blr + +/* + * Flush a particular page from the instruction cache. + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * + *	void __flush_icache_page(void *page) + */ +_GLOBAL(__flush_icache_page) +	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */ +	mtctr	r4 +1:	icbi	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	sync +	isync +	blr + +/* + * Clear a page using the dcbz instruction, which doesn't cause any + * memory traffic (except to write out any cache lines which get + * displaced).  This only works on cacheable memory. + */ +_GLOBAL(clear_page) +	li	r0,4096/CACHE_LINE_SIZE +	mtctr	r0 +1:	dcbz	0,r3 +	addi	r3,r3,CACHE_LINE_SIZE +	bdnz	1b +	blr + +/* + * Enable L1 Instruction cache + */ +_GLOBAL(icache_enable) +	mfspr	r3, HID0 +	li	r5, HID0_ICFI|HID0_ILOCK +	andc	r3, r3, r5 +	ori	r3, r3, HID0_ICE +	ori	r5, r3, HID0_ICFI +	mtspr	HID0, r5 +	mtspr	HID0, r3 +	isync +	blr + +/* + * Disable L1 Instruction cache + */ +_GLOBAL(icache_disable) +	mfspr	r3, HID0 +	li	r5, 0 +	ori	r5, r5, HID0_ICE +	andc	r3, r3, r5 +	mtspr	HID0, r3 +	isync +	blr + +/* + * Is instruction cache enabled? + */ +_GLOBAL(icache_status) +	mfspr	r3, HID0 +	andi.	r3, r3, HID0_ICE +	blr + + +_GLOBAL(l1dcache_enable) +	mfspr	r3, HID0 +	li	r5, HID0_DCFI|HID0_DLOCK +	andc	r3, r3, r5 +	mtspr	HID0, r3		/* no invalidate, unlock */ +	ori	r3, r3, HID0_DCE +	ori	r5, r3, HID0_DCFI +	mtspr	HID0, r5		/* enable + invalidate */ +	mtspr	HID0, r3		/* enable */ +	sync +	blr + +/* + * Enable data cache(s) - L1 and optionally L2 + * Calls l2cache_enable. LR saved in r5 + */ +_GLOBAL(dcache_enable) +	mfspr	r3, HID0 +	li	r5, HID0_DCFI|HID0_DLOCK +	andc	r3, r3, r5 +	mtspr	HID0, r3		/* no invalidate, unlock */ +	ori	r3, r3, HID0_DCE +	ori	r5, r3, HID0_DCFI +	mtspr	HID0, r5		/* enable + invalidate */ +	mtspr	HID0, r3		/* enable */ +	sync +#ifdef CFG_L2 +	mflr	r5 +	bl	l2cache_enable		/* uses r3 and r4 */ +	sync +	mtlr	r5 +#endif +	blr + + +/* + * Disable data cache(s) - L1 and optionally L2 + * Calls flush_data_cache and l2cache_disable_no_flush. + * LR saved in r4 + */ +_GLOBAL(dcache_disable) +	mflr	r4			/* save link register */ +	bl	flush_data_cache	/* uses r3 and r5 */ +	sync +	mfspr	r3, HID0 +	li	r5, HID0_DCFI|HID0_DLOCK +	andc	r3, r3, r5 +	mtspr	HID0, r3		/* no invalidate, unlock */ +	li	r5, HID0_DCE|HID0_DCFI +	andc	r3, r3, r5		/* no enable, no invalidate */ +	mtspr	HID0, r3 +	sync +#ifdef CFG_L2 +	bl	l2cache_disable_no_flush /* uses r3 */ +#endif +	mtlr	r4			/* restore link register */ +	blr + +/* + * Is data cache enabled? + */ +_GLOBAL(dcache_status) +	mfspr	r3, HID0 +	andi.	r3, r3, HID0_DCE +	blr + +/* + * Invalidate L2 cache using L2I, assume L2 is enabled + */ +_GLOBAL(l2cache_invalidate) +	mfspr	r3, l2cr +	rlwinm.	r3, r3, 0, 0, 0 +	beq	1f + +	mfspr	r3, l2cr +	rlwinm	r3, r3, 0, 1, 31 + +#ifdef	CONFIG_ALTIVEC +	dssall +#endif +	sync +	mtspr	l2cr, r3 +	sync +1:	mfspr	r3, l2cr +	oris	r3, r3, L2CR_L2I@h +	mtspr	l2cr, r3 + +invl2: +	mfspr	r3, l2cr +	andi.	r3, r3, L2CR_L2I@h +	bne	invl2 +	blr + +/* + * Enable L2 cache + * Calls l2cache_invalidate. LR is saved in r4 + */ +_GLOBAL(l2cache_enable) +	mflr	r4			/* save link register */ +	bl	l2cache_invalidate	/* uses r3 */ +	sync +	lis	r3, L2_ENABLE@h +	ori	r3, r3, L2_ENABLE@l +	mtspr	l2cr, r3 +	isync +	mtlr	r4			/* restore link register */ +	blr + +/* + * Disable L2 cache + * Calls flush_data_cache. LR is saved in r4 + */ +_GLOBAL(l2cache_disable) +	mflr	r4			/* save link register */ +	bl	flush_data_cache	/* uses r3 and r5 */ +	sync +	mtlr	r4			/* restore link register */ +l2cache_disable_no_flush:		/* provide way to disable L2 w/o flushing */ +	lis	r3, L2_INIT@h +	ori	r3, r3, L2_INIT@l +	mtspr	l2cr, r3 +	isync +	blr diff --git a/cpu/mpc86xx/config.mk b/cpu/mpc86xx/config.mk new file mode 100644 index 000000000..3c54f4ad3 --- /dev/null +++ b/cpu/mpc86xx/config.mk @@ -0,0 +1,26 @@ +# +# (C) Copyright 2004 Freescale Semiconductor. +# Jeff Brown +# +# 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 -ffixed-r14 -meabi + +PLATFORM_CPPFLAGS += -DCONFIG_MPC86xx -ffixed-r2 -ffixed-r29 -mstring diff --git a/cpu/mpc86xx/cpu.c b/cpu/mpc86xx/cpu.c new file mode 100644 index 000000000..551b24307 --- /dev/null +++ b/cpu/mpc86xx/cpu.c @@ -0,0 +1,308 @@ +/* + * Copyright 2006 Freescale Semiconductor + * Jeff Brown + * Srikanth Srinivasan (srikanth.srinivasan@freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <watchdog.h> +#include <command.h> +#include <asm/cache.h> +#include <mpc86xx.h> + +#if defined(CONFIG_OF_FLAT_TREE) +#include <ft_build.h> +#endif + +#ifdef CONFIG_MPC8641HPCN +extern void mpc8641_reset_board(cmd_tbl_t *cmdtp, int flag, +				int argc, char *argv[]); +#endif + + +int +checkcpu(void) +{ +	sys_info_t sysinfo; +	uint pvr, svr; +	uint ver; +	uint major, minor; +	uint lcrr;		/* local bus clock ratio register */ +	uint clkdiv;		/* clock divider portion of lcrr */ + +	puts("Freescale PowerPC\n"); + +	pvr = get_pvr(); +	ver = PVR_VER(pvr); +	major = PVR_MAJ(pvr); +	minor = PVR_MIN(pvr); + +	puts("CPU:\n"); +	puts("    Core: "); + +	switch (ver) { +	case PVR_VER(PVR_86xx): +		puts("E600"); +		break; +	default: +		puts("Unknown"); +		break; +	} +	printf(", Version: %d.%d, (0x%08x)\n", major, minor, pvr); + +	svr = get_svr(); +	ver = SVR_VER(svr); +	major = SVR_MAJ(svr); +	minor = SVR_MIN(svr); + +	puts("    System: "); +	switch (ver) { +	case SVR_8641: +	    if (SVR_SUBVER(svr) == 1) { +		puts("8641D"); +	    } else { +		puts("8641"); +	    } +	    break; +	default: +		puts("Unknown"); +		break; +	} +	printf(", Version: %d.%d, (0x%08x)\n", major, minor, svr); + +	get_sys_info(&sysinfo); + +	puts("    Clocks: "); +	printf("CPU:%4lu MHz, ", sysinfo.freqProcessor / 1000000); +	printf("MPX:%4lu MHz, ", sysinfo.freqSystemBus / 1000000); +	printf("DDR:%4lu MHz, ", sysinfo.freqSystemBus / 2000000); + +#if defined(CFG_LBC_LCRR) +	lcrr = CFG_LBC_LCRR; +#else +	{ +		volatile immap_t *immap = (immap_t *) CFG_IMMR; +		volatile ccsr_lbc_t *lbc = &immap->im_lbc; + +		lcrr = lbc->lcrr; +	} +#endif +	clkdiv = lcrr & 0x0f; +	if (clkdiv == 2 || clkdiv == 4 || clkdiv == 8) { +		printf("LBC:%4lu MHz\n", +		       sysinfo.freqSystemBus / 1000000 / clkdiv); +	} else { +		printf("    LBC: unknown (lcrr: 0x%08x)\n", lcrr); +	} + +	puts("    L2: "); +	if (get_l2cr() & 0x80000000) +		puts("Enabled\n"); +	else +		puts("Disabled\n"); + +	return 0; +} + + +static inline void +soft_restart(unsigned long addr) +{ +#ifndef CONFIG_MPC8641HPCN + +	/* +	 * SRR0 has system reset vector, SRR1 has default MSR value +	 * rfi restores MSR from SRR1 and sets the PC to the SRR0 value +	 */ + +	__asm__ __volatile__ ("mtspr	26, %0"		:: "r" (addr)); +	__asm__ __volatile__ ("li	4, (1 << 6)"	::: "r4"); +	__asm__ __volatile__ ("mtspr	27, 4"); +	__asm__ __volatile__ ("rfi"); + +#else /* CONFIG_MPC8641HPCN */ + +	out8(PIXIS_BASE + PIXIS_RST, 0); + +#endif /* !CONFIG_MPC8641HPCN */ + +	while (1) ;		/* not reached */ +} + + +/* + * No generic way to do board reset. Simply call soft_reset. + */ +void +do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +#ifndef CONFIG_MPC8641HPCN + +#ifdef CFG_RESET_ADDRESS +	ulong addr = CFG_RESET_ADDRESS; +#else +	/* +	 * note: when CFG_MONITOR_BASE points to a RAM address, +	 * CFG_MONITOR_BASE - sizeof (ulong) is usually a valid +	 * address. Better pick an address known to be invalid on your +	 * system and assign it to CFG_RESET_ADDRESS. +	 */ +	ulong addr = CFG_MONITOR_BASE - sizeof(ulong); +#endif + +	/* flush and disable I/D cache */ +	__asm__ __volatile__ ("mfspr	3, 1008"	::: "r3"); +	__asm__ __volatile__ ("ori	5, 5, 0xcc00"	::: "r5"); +	__asm__ __volatile__ ("ori	4, 3, 0xc00"	::: "r4"); +	__asm__ __volatile__ ("andc	5, 3, 5"	::: "r5"); +	__asm__ __volatile__ ("sync"); +	__asm__ __volatile__ ("mtspr	1008, 4"); +	__asm__ __volatile__ ("isync"); +	__asm__ __volatile__ ("sync"); +	__asm__ __volatile__ ("mtspr	1008, 5"); +	__asm__ __volatile__ ("isync"); +	__asm__ __volatile__ ("sync"); + +	soft_restart(addr); + +#else /* CONFIG_MPC8641HPCN */ + +	mpc8641_reset_board(cmdtp, flag, argc, argv); + +#endif /* !CONFIG_MPC8641HPCN */ + +	while (1) ;		/* not reached */ +} + + +/* + * Get timebase clock frequency + */ +unsigned long +get_tbclk(void) +{ +	sys_info_t sys_info; + +	get_sys_info(&sys_info); +	return (sys_info.freqSystemBus + 3L) / 4L; +} + + +#if defined(CONFIG_WATCHDOG) +void +watchdog_reset(void) +{ +} +#endif	/* CONFIG_WATCHDOG */ + + +#if defined(CONFIG_DDR_ECC) +void +dma_init(void) +{ +	volatile immap_t *immap = (immap_t *) CFG_IMMR; +	volatile ccsr_dma_t *dma = &immap->im_dma; + +	dma->satr0 = 0x00040000; +	dma->datr0 = 0x00040000; +	asm("sync; isync"); +} + +uint +dma_check(void) +{ +	volatile immap_t *immap = (immap_t *) CFG_IMMR; +	volatile ccsr_dma_t *dma = &immap->im_dma; +	volatile uint status = dma->sr0; + +	/* While the channel is busy, spin */ +	while ((status & 4) == 4) { +		status = dma->sr0; +	} + +	if (status != 0) { +		printf("DMA Error: status = %x\n", status); +	} +	return status; +} + +int +dma_xfer(void *dest, uint count, void *src) +{ +	volatile immap_t *immap = (immap_t *) CFG_IMMR; +	volatile ccsr_dma_t *dma = &immap->im_dma; + +	dma->dar0 = (uint) dest; +	dma->sar0 = (uint) src; +	dma->bcr0 = count; +	dma->mr0 = 0xf000004; +	asm("sync;isync"); +	dma->mr0 = 0xf000005; +	asm("sync;isync"); +	return dma_check(); +} + +#endif	/* CONFIG_DDR_ECC */ + + +#ifdef CONFIG_OF_FLAT_TREE +void +ft_cpu_setup(void *blob, bd_t *bd) +{ +	u32 *p; +	ulong clock; +	int len; + +	clock = bd->bi_busfreq; +	p = ft_get_prop(blob, "/cpus/" OF_CPU "/bus-frequency", &len); +	if (p != NULL) +		*p = cpu_to_be32(clock); + +	p = ft_get_prop(blob, "/" OF_SOC "/serial@4500/clock-frequency", &len); +	if (p != NULL) +		*p = cpu_to_be32(clock); + +	p = ft_get_prop(blob, "/" OF_SOC "/serial@4600/clock-frequency", &len); +	if (p != NULL) +		*p = cpu_to_be32(clock); + +#if defined(CONFIG_MPC86XX_TSEC1) +	p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/mac-address", &len); +	memcpy(p, bd->bi_enetaddr, 6); +#endif + +#if defined(CONFIG_MPC86XX_TSEC2) +	p = ft_get_prop(blob, "/" OF_SOC "/ethernet@25000/mac-address", &len); +	memcpy(p, bd->bi_enet1addr, 6); +#endif + +#if defined(CONFIG_MPC86XX_TSEC3) +	p = ft_get_prop(blob, "/" OF_SOC "/ethernet@26000/mac-address", &len); +	memcpy(p, bd->bi_enet2addr, 6); +#endif + +#if defined(CONFIG_MPC86XX_TSEC4) +	p = ft_get_prop(blob, "/" OF_SOC "/ethernet@27000/mac-address", &len); +	memcpy(p, bd->bi_enet3addr, 6); +#endif + +} +#endif diff --git a/cpu/mpc86xx/cpu_init.c b/cpu/mpc86xx/cpu_init.c new file mode 100644 index 000000000..4673d05e7 --- /dev/null +++ b/cpu/mpc86xx/cpu_init.c @@ -0,0 +1,117 @@ +/* + * Copyright 2004 Freescale Semiconductor. + * Jeff Brown + * Srikanth Srinivasan (srikanth.srinivasan@freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * cpu_init.c - low level cpu init + */ + +#include <common.h> +#include <mpc86xx.h> + +/* + * Breathe some life into the CPU... + * + * Set up the memory map + * initialize a bunch of registers + */ + +void cpu_init_f(void) +{ +	DECLARE_GLOBAL_DATA_PTR; +	volatile immap_t    *immap = (immap_t *)CFG_IMMR; +	volatile ccsr_lbc_t *memctl = &immap->im_lbc; + +	/* Pointer is writable since we allocated a register for it */ +	gd = (gd_t *) (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET); + +	/* Clear initial global data */ +	memset ((void *) gd, 0, sizeof (gd_t)); + +	/* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary +	 * addresses - these have to be modified later when FLASH size +	 * has been determined +	 */ + +#if defined(CFG_OR0_REMAP) +	memctl->or0 = CFG_OR0_REMAP; +#endif +#if defined(CFG_OR1_REMAP) +	memctl->or1 = CFG_OR1_REMAP; +#endif + +	/* now restrict to preliminary range */ +#if defined(CFG_BR0_PRELIM) && defined(CFG_OR0_PRELIM) +	memctl->br0 = CFG_BR0_PRELIM; +	memctl->or0 = CFG_OR0_PRELIM; +#endif + +#if defined(CFG_BR1_PRELIM) && defined(CFG_OR1_PRELIM) +	memctl->or1 = CFG_OR1_PRELIM; +	memctl->br1 = CFG_BR1_PRELIM; +#endif + +#if defined(CFG_BR2_PRELIM) && defined(CFG_OR2_PRELIM) +	memctl->or2 = CFG_OR2_PRELIM; +	memctl->br2 = CFG_BR2_PRELIM; +#endif + +#if defined(CFG_BR3_PRELIM) && defined(CFG_OR3_PRELIM) +	memctl->or3 = CFG_OR3_PRELIM; +	memctl->br3 = CFG_BR3_PRELIM; +#endif + +#if defined(CFG_BR4_PRELIM) && defined(CFG_OR4_PRELIM) +	memctl->or4 = CFG_OR4_PRELIM; +	memctl->br4 = CFG_BR4_PRELIM; +#endif + +#if defined(CFG_BR5_PRELIM) && defined(CFG_OR5_PRELIM) +	memctl->or5 = CFG_OR5_PRELIM; +	memctl->br5 = CFG_BR5_PRELIM; +#endif + +#if defined(CFG_BR6_PRELIM) && defined(CFG_OR6_PRELIM) +	memctl->or6 = CFG_OR6_PRELIM; +	memctl->br6 = CFG_BR6_PRELIM; +#endif + +#if defined(CFG_BR7_PRELIM) && defined(CFG_OR7_PRELIM) +	memctl->or7 = CFG_OR7_PRELIM; +	memctl->br7 = CFG_BR7_PRELIM; +#endif + +	/* enable the timebase bit in HID0 */ +	set_hid0(get_hid0() | 0x4000000); + +	/* enable SYNCBE | ABE bits in  HID1 */ +	set_hid1(get_hid1() | 0x00000C00); +} + +/* + * initialize higher level parts of CPU like timers + */ +int cpu_init_r(void) +{ +	return 0; +} diff --git a/cpu/mpc86xx/interrupts.c b/cpu/mpc86xx/interrupts.c new file mode 100644 index 000000000..1df6cdc5b --- /dev/null +++ b/cpu/mpc86xx/interrupts.c @@ -0,0 +1,204 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2002 (440 port) + * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com + * + * (C) Copyright 2003 Motorola Inc. (MPC85xx port) + * Xianghua Xiao (X.Xiao@motorola.com) + * + * (C) Copyright 2004 Freescale Semiconductor. (MPC86xx Port) + * Jeff Brown + * Srikanth Srinivasan (srikanth.srinivasan@freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <mpc86xx.h> +#include <command.h> +#include <asm/processor.h> +#include <ppc_asm.tmpl> + +unsigned long decrementer_count;    /* count value for 1e6/HZ microseconds */ +unsigned long timestamp; + + +static __inline__ unsigned long get_msr(void) +{ +	unsigned long msr; + +	asm volatile ("mfmsr %0":"=r" (msr):); + +	return msr; +} + +static __inline__ void set_msr(unsigned long msr) +{ +	asm volatile ("mtmsr %0"::"r" (msr)); +} + +static __inline__ unsigned long get_dec(void) +{ +	unsigned long val; + +	asm volatile ("mfdec %0":"=r" (val):); + +	return val; +} + +static __inline__ void set_dec(unsigned long val) +{ +	if (val) +		asm volatile ("mtdec %0"::"r" (val)); +} + +/* interrupt is not supported yet */ +int interrupt_init_cpu(unsigned *decrementer_count) +{ +	return 0; +} + +int interrupt_init(void) +{ +	int ret; + +	/* call cpu specific function from $(CPU)/interrupts.c */ +	ret = interrupt_init_cpu(&decrementer_count); + +	if (ret) +		return ret; + +	decrementer_count = get_tbclk() / CFG_HZ; +	debug("interrupt init: tbclk() = %d MHz, decrementer_count = %d\n", +	      (get_tbclk() / 1000000), +	      decrementer_count); + +	set_dec(decrementer_count); + +	set_msr(get_msr() | MSR_EE); + +	debug("MSR = 0x%08lx, Decrementer reg = 0x%08lx\n", +	      get_msr(), +	      get_dec()); + +	return 0; +} + +void enable_interrupts(void) +{ +	set_msr(get_msr() | MSR_EE); +} + +/* returns flag if MSR_EE was set before */ +int disable_interrupts(void) +{ +	ulong msr = get_msr(); + +	set_msr(msr & ~MSR_EE); +	return (msr & MSR_EE) != 0; +} + +void increment_timestamp(void) +{ +	timestamp++; +} + +/* + * timer_interrupt - gets called when the decrementer overflows, + * with interrupts disabled. + * Trivial implementation - no need to be really accurate. + */ +void timer_interrupt_cpu(struct pt_regs *regs) +{ +	/* nothing to do here */ +} + +void timer_interrupt(struct pt_regs *regs) +{ +	/* call cpu specific function from $(CPU)/interrupts.c */ +	timer_interrupt_cpu(regs); + +	timestamp++; + +	ppcDcbf(×tamp); + +	/* Restore Decrementer Count */ +	set_dec(decrementer_count); + +#if defined(CONFIG_WATCHDOG) || defined (CONFIG_HW_WATCHDOG) +	if ((timestamp % (CFG_WATCHDOG_FREQ)) == 0) +		WATCHDOG_RESET(); +#endif /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */ + +#ifdef CONFIG_STATUS_LED +	status_led_tick(timestamp); +#endif /* CONFIG_STATUS_LED */ + +#ifdef CONFIG_SHOW_ACTIVITY +	board_show_activity(timestamp); +#endif /* CONFIG_SHOW_ACTIVITY */ + +} + +void reset_timer(void) +{ +	timestamp = 0; +} + +ulong get_timer(ulong base) +{ +	return timestamp - base; +} + +void set_timer(ulong t) +{ +	timestamp = t; +} + +/* + * Install and free a interrupt handler. Not implemented yet. + */ + +void irq_install_handler(int vec, interrupt_handler_t *handler, void *arg) +{ +} + +void irq_free_handler(int vec) +{ +} + +/* + * irqinfo - print information about PCI devices,not implemented. + */ +int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	printf("\nInterrupt-unsupported:\n"); + +	return 0; +} + +/* + * Handle external interrupts + */ +void external_interrupt(struct pt_regs *regs) +{ +	puts("external_interrupt (oops!)\n"); +} diff --git a/cpu/mpc86xx/pci.c b/cpu/mpc86xx/pci.c new file mode 100644 index 000000000..b86548db4 --- /dev/null +++ b/cpu/mpc86xx/pci.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) Freescale Semiconductor,Inc. + * 2005, 2006. All rights reserved. + * + * Ed Swarthout (ed.swarthout@freescale.com) + * Jason Jin (Jason.jin@freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * PCIE Configuration space access support for PCIE Bridge + */ +#include <common.h> +#include <pci.h> + +#if defined(CONFIG_PCI) +void +pci_mpc86xx_init(struct pci_controller *hose) +{ +	volatile immap_t *immap = (immap_t *) CFG_CCSRBAR; +	volatile ccsr_pex_t *pcie1 = &immap->im_pex1; +	u16 temp16; +	u32 temp32; + +	volatile ccsr_gur_t *gur = &immap->im_gur; +	uint host1_agent = (gur->porbmsr & MPC86xx_PORBMSR_HA) >> 17; +	uint pcie1_host = (host1_agent == 2) || (host1_agent == 3); +	uint pcie1_agent = (host1_agent == 0) || (host1_agent == 1); +	uint devdisr = gur->devdisr; +	uint io_sel = (gur->pordevsr & MPC86xx_PORDEVSR_IO_SEL) >> 16; + +	if ((io_sel == 2 || io_sel == 3 || io_sel == 5 || io_sel == 6 || +	     io_sel == 7 || io_sel == 0xf) +	    && !(devdisr & MPC86xx_DEVDISR_PCIEX1)) { +		printf("PCI-EXPRESS 1: Configured as %s \n", +		       pcie1_agent ? "Agent" : "Host"); +		if (pcie1_agent) +			return;	/*Don't scan bus when configured as agent */ +		printf("               Scanning PCIE bus"); +		debug("0x%08x=0x%08x ", +		      &pcie1->pme_msg_det, +		      pcie1->pme_msg_det); +		if (pcie1->pme_msg_det) { +			pcie1->pme_msg_det = 0xffffffff; +			debug(" with errors.  Clearing.  Now 0x%08x", +			      pcie1->pme_msg_det); +		} +		debug("\n"); +	} else { +		printf("PCI-EXPRESS 1 disabled!\n"); +		return; +	} + +	/* +	 * Set first_bus=0 only skipped B0:D0:F0 which is +	 * a reserved device in M1575, but make it easy for +	 * most of the scan process. +	 */ +	hose->first_busno = 0x00; +	hose->last_busno = 0xfe; + +	pcie_setup_indirect(hose, (CFG_IMMR + 0x8000), (CFG_IMMR + 0x8004)); + +	pci_hose_read_config_word(hose, +				  PCI_BDF(0, 0, 0), PCI_COMMAND, &temp16); +	temp16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | +	    PCI_COMMAND_MEMORY | PCI_COMMAND_IO; +	pci_hose_write_config_word(hose, +				   PCI_BDF(0, 0, 0), PCI_COMMAND, temp16); + +	pci_hose_write_config_word(hose, PCI_BDF(0, 0, 0), PCI_STATUS, 0xffff); +	pci_hose_write_config_byte(hose, +				   PCI_BDF(0, 0, 0), PCI_LATENCY_TIMER, 0x80); + +	pci_hose_read_config_dword(hose, PCI_BDF(0, 0, 0), PCI_PRIMARY_BUS, +				   &temp32); +	temp32 = (temp32 & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16); +	pci_hose_write_config_dword(hose, PCI_BDF(0, 0, 0), PCI_PRIMARY_BUS, +				    temp32); + +	pcie1->powar1 = 0; +	pcie1->powar2 = 0; +	pcie1->piwar1 = 0; +	pcie1->piwar1 = 0; + +	pcie1->powbar1 = (CFG_PCI1_MEM_BASE >> 12) & 0x000fffff; +	pcie1->powar1 = 0x8004401c;	/* 512M MEM space */ +	pcie1->potar1 = (CFG_PCI1_MEM_BASE >> 12) & 0x000fffff; +	pcie1->potear1 = 0x00000000; + +	pcie1->powbar2 = (CFG_PCI1_IO_BASE >> 12) & 0x000fffff; +	pcie1->powar2 = 0x80088017;	/* 16M IO space */ +	pcie1->potar2 = 0x00000000; +	pcie1->potear2 = 0x00000000; + +	pcie1->pitar1 = 0x00000000; +	pcie1->piwbar1 = 0x00000000; +	/* Enable, Prefetch, Local Mem, * Snoop R/W, 2G */ +	pcie1->piwar1 = 0xa0f5501e; + +	pci_set_region(hose->regions + 0, +		       CFG_PCI_MEMORY_BUS, +		       CFG_PCI_MEMORY_PHYS, +		       CFG_PCI_MEMORY_SIZE, +		       PCI_REGION_MEM | PCI_REGION_MEMORY); + +	pci_set_region(hose->regions + 1, +		       CFG_PCI1_MEM_BASE, +		       CFG_PCI1_MEM_PHYS, +		       CFG_PCI1_MEM_SIZE, +		       PCI_REGION_MEM); + +	pci_set_region(hose->regions + 2, +		       CFG_PCI1_IO_BASE, +		       CFG_PCI1_IO_PHYS, +		       CFG_PCI1_IO_SIZE, +		       PCI_REGION_IO); + +	hose->region_count = 3; + +	pci_register_hose(hose); + +	hose->last_busno = pci_hose_scan(hose); +	debug("pcie_mpc86xx_init: last_busno %x\n", hose->last_busno); +	debug("pcie_mpc86xx init: current_busno %x\n ", hose->current_busno); + +	printf("....PCIE1 scan & enumeration done\n"); +} +#endif				/* CONFIG_PCI */ diff --git a/cpu/mpc86xx/pcie_indirect.c b/cpu/mpc86xx/pcie_indirect.c new file mode 100644 index 000000000..b00ad76ab --- /dev/null +++ b/cpu/mpc86xx/pcie_indirect.c @@ -0,0 +1,199 @@ +/* + * Support for indirect PCI bridges. + * + * Copyright (c) Freescale Semiconductor, Inc. + * 2006. All rights reserved. + * + * Jason Jin <Jason.jin@freescale.com> + * + * 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. + * + * partly derived from + * arch/powerpc/platforms/86xx/mpc86xx_pcie.c + */ + +#include <common.h> + +#ifdef CONFIG_PCI + +#include <asm/processor.h> +#include <asm/io.h> +#include <pci.h> + +#define PCI_CFG_OUT 	out_be32 +#define PEX_FIX		out_be32(hose->cfg_addr+0x4, 0x0400ffff) + +static int +indirect_read_config_pcie(struct pci_controller *hose, +			  pci_dev_t dev, +			  int offset, +			  int len, +			  u32 *val) +{ +	int bus = PCI_BUS(dev); + +	volatile unsigned char *cfg_data; +	u32 temp; + +	PEX_FIX; +	if (bus == 0xff) { +		PCI_CFG_OUT(hose->cfg_addr, +			    dev | (offset & 0xfc) | 0x80000001); +	} else { +		PCI_CFG_OUT(hose->cfg_addr, +			    dev | (offset & 0xfc) | 0x80000000); +	} +	/* +	 * Note: the caller has already checked that offset is +	 * suitably aligned and that len is 1, 2 or 4. +	 */ +	/* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */ +	cfg_data = hose->cfg_data; +	PEX_FIX; +	temp = in_le32((u32 *) cfg_data); +	switch (len) { +	case 1: +		*val = (temp >> (((offset & 3)) * 8)) & 0xff; +		break; +	case 2: +		*val = (temp >> (((offset & 3)) * 8)) & 0xffff; +		break; +	default: +		*val = temp; +		break; +	} + +	return 0; +} + +static int +indirect_write_config_pcie(struct pci_controller *hose, +			   pci_dev_t dev, +			   int offset, +			   int len, +			   u32 val) +{ +	int bus = PCI_BUS(dev); +	volatile unsigned char *cfg_data; +	u32 temp; + +	PEX_FIX; +	if (bus == 0xff) { +		PCI_CFG_OUT(hose->cfg_addr, +			    dev | (offset & 0xfc) | 0x80000001); +	} else { +		PCI_CFG_OUT(hose->cfg_addr, +			    dev | (offset & 0xfc) | 0x80000000); +	} + +	/* +	 * Note: the caller has already checked that offset is +	 * suitably aligned and that len is 1, 2 or 4. +	 */ +	/* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */ +	cfg_data = hose->cfg_data; +	switch (len) { +	case 1: +		PEX_FIX; +		temp = in_le32((u32 *) cfg_data); +		temp = (temp & ~(0xff << ((offset & 3) * 8))) | +		    (val << ((offset & 3) * 8)); +		PEX_FIX; +		out_le32((u32 *) cfg_data, temp); +		break; +	case 2: +		PEX_FIX; +		temp = in_le32((u32 *) cfg_data); +		temp = (temp & ~(0xffff << ((offset & 3) * 8))); +		temp |= (val << ((offset & 3) * 8)); +		PEX_FIX; +		out_le32((u32 *) cfg_data, temp); +		break; +	default: +		PEX_FIX; +		out_le32((u32 *) cfg_data, val); +		break; +	} +	PEX_FIX; +	return 0; +} + +static int +indirect_read_config_byte_pcie(struct pci_controller *hose, +			       pci_dev_t dev, +			       int offset, +			       u8 *val) +{ +	u32 val32; +	indirect_read_config_pcie(hose, dev, offset, 1, &val32); +	*val = (u8) val32; +	return 0; +} + +static int +indirect_read_config_word_pcie(struct pci_controller *hose, +			       pci_dev_t dev, +			       int offset, +			       u16 *val) +{ +	u32 val32; +	indirect_read_config_pcie(hose, dev, offset, 2, &val32); +	*val = (u16) val32; +	return 0; +} + +static int +indirect_read_config_dword_pcie(struct pci_controller *hose, +				pci_dev_t dev, +				int offset, +				u32 *val) +{ +	return indirect_read_config_pcie(hose, dev, offset, 4, val); +} + +static int +indirect_write_config_byte_pcie(struct pci_controller *hose, +				pci_dev_t dev, +				int offset, +				u8 val) +{ +	return indirect_write_config_pcie(hose, dev, offset, 1, (u32) val); +} + +static int +indirect_write_config_word_pcie(struct pci_controller *hose, +				pci_dev_t dev, +				int offset, +				unsigned short val) +{ +	return indirect_write_config_pcie(hose, dev, offset, 2, (u32) val); +} + +static int +indirect_write_config_dword_pcie(struct pci_controller *hose, +				 pci_dev_t dev, +				 int offset, +				 u32 val) +{ +	return indirect_write_config_pcie(hose, dev, offset, 4, val); +} + +void +pcie_setup_indirect(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data) +{ +	pci_set_ops(hose, +		    indirect_read_config_byte_pcie, +		    indirect_read_config_word_pcie, +		    indirect_read_config_dword_pcie, +		    indirect_write_config_byte_pcie, +		    indirect_write_config_word_pcie, +		    indirect_write_config_dword_pcie); + +	hose->cfg_addr = (unsigned int *)cfg_addr; +	hose->cfg_data = (unsigned char *)cfg_data; +} + +#endif				/* CONFIG_PCI */ diff --git a/cpu/mpc86xx/resetvec.S b/cpu/mpc86xx/resetvec.S new file mode 100644 index 000000000..9a552f662 --- /dev/null +++ b/cpu/mpc86xx/resetvec.S @@ -0,0 +1,2 @@ +	.section .resetvec,"ax" +	b _start diff --git a/cpu/mpc86xx/spd_sdram.c b/cpu/mpc86xx/spd_sdram.c new file mode 100644 index 000000000..b18e8225d --- /dev/null +++ b/cpu/mpc86xx/spd_sdram.c @@ -0,0 +1,1320 @@ +/* + * Copyright 2004 Freescale Semiconductor. + * (C) Copyright 2003 Motorola Inc. + * Xianghua Xiao (X.Xiao@motorola.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/processor.h> +#include <i2c.h> +#include <spd.h> +#include <asm/mmu.h> + + +#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) +extern void dma_init(void); +extern uint dma_check(void); +extern int dma_xfer(void *dest, uint count, void *src); +#endif + +#ifdef CONFIG_SPD_EEPROM + +#ifndef	CFG_READ_SPD +#define CFG_READ_SPD	i2c_read +#endif + +/* + * Only one of the following three should be 1; others should be 0 + * By default the cache line interleaving is selected if + * the CONFIG_DDR_INTERLEAVE flag is defined + */ +#define CFG_PAGE_INTERLEAVING		0 +#define CFG_BANK_INTERLEAVING		0 +#define CFG_SUPER_BANK_INTERLEAVING	0 + +/* + * Convert picoseconds into clock cycles (rounding up if needed). + */ + +int +picos_to_clk(int picos) +{ +	int clks; + +	clks = picos / (2000000000 / (get_bus_freq(0) / 1000)); +	if (picos % (2000000000 / (get_bus_freq(0) / 1000)) != 0) { +		clks++; +	} + +	return clks; +} + + +/* + * Calculate the Density of each Physical Rank. + * Returned size is in bytes. + * + * Study these table from Byte 31 of JEDEC SPD Spec. + * + *		DDR I	DDR II + *	Bit	Size	Size + *	---	-----	------ + *	7 high	512MB	512MB + *	6	256MB	256MB + *	5	128MB	128MB + *	4	 64MB	 16GB + *	3	 32MB	  8GB + *	2	 16MB	  4GB + *	1	  2GB	  2GB + *	0 low	  1GB	  1GB + * + * Reorder Table to be linear by stripping the bottom + * 2 or 5 bits off and shifting them up to the top. + */ + +unsigned int +compute_banksize(unsigned int mem_type, unsigned char row_dens) +{ +	unsigned int bsize; + +	if (mem_type == SPD_MEMTYPE_DDR) { +		/* Bottom 2 bits up to the top. */ +		bsize = ((row_dens >> 2) | ((row_dens & 3) << 6)) << 24; +		debug("DDR: DDR I rank density = 0x%08x\n", bsize); +	} else { +		/* Bottom 5 bits up to the top. */ +		bsize = ((row_dens >> 5) | ((row_dens & 31) << 3)) << 27; +		debug("DDR: DDR II rank density = 0x%08x\n", bsize); +	} +	return bsize; +} + + +/* + * Convert a two-nibble BCD value into a cycle time. + * While the spec calls for nano-seconds, picos are returned. + * + * This implements the tables for bytes 9, 23 and 25 for both + * DDR I and II.  No allowance for distinguishing the invalid + * fields absent for DDR I yet present in DDR II is made. + * (That is, cycle times of .25, .33, .66 and .75 ns are + * allowed for both DDR II and I.) + */ + +unsigned int +convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val) +{ +	/* +	 * Table look up the lower nibble, allow DDR I & II. +	 */ +	unsigned int tenths_ps[16] = { +		0, +		100, +		200, +		300, +		400, +		500, +		600, +		700, +		800, +		900, +		250, +		330, +		660, +		750, +		0,	/* undefined */ +		0	/* undefined */ +	}; + +	unsigned int whole_ns = (spd_val & 0xF0) >> 4; +	unsigned int tenth_ns = spd_val & 0x0F; +	unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns]; + +	return ps; +} + + +/* + * Determine Refresh Rate.  Ignore self refresh bit on DDR I. + * Table from SPD Spec, Byte 12, converted to picoseconds and + * filled in with "default" normal values. + */ +unsigned int determine_refresh_rate(unsigned int spd_refresh) +{ +	unsigned int refresh_time_ns[8] = { +		15625000,	/* 0 Normal    1.00x */ +		3900000,	/* 1 Reduced    .25x */ +		7800000,	/* 2 Extended   .50x */ +		31300000,	/* 3 Extended  2.00x */ +		62500000,	/* 4 Extended  4.00x */ +		125000000,	/* 5 Extended  8.00x */ +		15625000,	/* 6 Normal    1.00x  filler */ +		15625000,	/* 7 Normal    1.00x  filler */ +	}; + +	return picos_to_clk(refresh_time_ns[spd_refresh & 0x7]); +} + + +long int +spd_init(unsigned char i2c_address, unsigned int ddr_num, +	 unsigned int dimm_num, unsigned int start_addr) +{ +	volatile immap_t *immap = (immap_t *)CFG_IMMR; +	volatile ccsr_ddr_t *ddr; +	volatile ccsr_gur_t *gur = &immap->im_gur; +	spd_eeprom_t spd; +	unsigned int n_ranks; +	unsigned int rank_density; +	unsigned int odt_rd_cfg, odt_wr_cfg; +	unsigned int odt_cfg, mode_odt_enable; +	unsigned int refresh_clk; +#ifdef MPC86xx_DDR_SDRAM_CLK_CNTL +	unsigned char clk_adjust; +#endif +	unsigned int dqs_cfg; +	unsigned char twr_clk, twtr_clk, twr_auto_clk; +	unsigned int tCKmin_ps, tCKmax_ps; +	unsigned int max_data_rate; +	unsigned int busfreq; +	unsigned int memsize; +	unsigned char caslat, caslat_ctrl; +	unsigned int trfc, trfc_clk, trfc_low, trfc_high; +	unsigned int trcd_clk; +	unsigned int trtp_clk; +	unsigned char cke_min_clk; +	unsigned char add_lat; +	unsigned char wr_lat; +	unsigned char wr_data_delay; +	unsigned char four_act; +	unsigned char cpo; +	unsigned char burst_len; +	unsigned int mode_caslat; +	unsigned char d_init; +	unsigned int tCycle_ps, modfreq; + +	if (ddr_num == 1) +		ddr = &immap->im_ddr1; +	else +		ddr = &immap->im_ddr2; + +	/* +	 * Read SPD information. +	 */ +	debug("Performing SPD read at I2C address 0x%02lx\n",i2c_address); +	memset((void *)&spd, 0, sizeof(spd)); +	CFG_READ_SPD(i2c_address, 0, 1, (uchar *) &spd, sizeof(spd)); + +	/* +	 * Check for supported memory module types. +	 */ +	if (spd.mem_type != SPD_MEMTYPE_DDR && +	    spd.mem_type != SPD_MEMTYPE_DDR2) { +		debug("Warning: Unable to locate DDR I or DDR II module for DIMM %d of DDR controller %d.\n" +		      "         Fundamental memory type is 0x%0x\n", +		      dimm_num, +		      ddr_num, +		      spd.mem_type); +		return 0; +	} + +	debug("\nFound memory of type 0x%02lx  ", spd.mem_type); +	if (spd.mem_type == SPD_MEMTYPE_DDR) +		debug("DDR I\n"); +	else +		debug("DDR II\n"); + +	/* +	 * These test gloss over DDR I and II differences in interpretation +	 * of bytes 3 and 4, but irrelevantly.  Multiple asymmetric banks +	 * are not supported on DDR I; and not encoded on DDR II. +	 * +	 * Also note that the 8548 controller can support: +	 *    12 <= nrow <= 16 +	 * and +	 *     8 <= ncol <= 11 (still, for DDR) +	 *     6 <= ncol <=  9 (for FCRAM) +	 */ +	if (spd.nrow_addr < 12 || spd.nrow_addr > 14) { +		printf("DDR: Unsupported number of Row Addr lines: %d.\n", +		       spd.nrow_addr); +		return 0; +	} +	if (spd.ncol_addr < 8 || spd.ncol_addr > 11) { +		printf("DDR: Unsupported number of Column Addr lines: %d.\n", +		       spd.ncol_addr); +		return 0; +	} + +	/* +	 * Determine the number of physical banks controlled by +	 * different Chip Select signals.  This is not quite the +	 * same as the number of DIMM modules on the board.  Feh. +	 */ +	if (spd.mem_type == SPD_MEMTYPE_DDR) { +		n_ranks = spd.nrows; +	} else { +		n_ranks = (spd.nrows & 0x7) + 1; +	} + +	debug("DDR: number of ranks = %d\n", n_ranks); + +	if (n_ranks > 2) { +		printf("DDR: Only 2 chip selects are supported: %d\n", +		       n_ranks); +		return 0; +	} + +	/* +	 * Adjust DDR II IO voltage biasing.  It just makes it work. +	 */ +	if (spd.mem_type == SPD_MEMTYPE_DDR2) { +		gur->ddrioovcr = (0 +				  | 0x80000000		/* Enable */ +				  | 0x10000000		/* VSEL to 1.8V */ +				  ); +	} + +	/* +	 * Determine the size of each Rank in bytes. +	 */ +	rank_density = compute_banksize(spd.mem_type, spd.row_dens); + +	debug("Start address for this controller is 0x%08lx\n", start_addr); + +	/* +	 * ODT configuration recommendation from DDR Controller Chapter. +	 */ +	odt_rd_cfg = 0;			/* Never assert ODT */ +	odt_wr_cfg = 0;			/* Never assert ODT */ +	if (spd.mem_type == SPD_MEMTYPE_DDR2) { +		odt_wr_cfg = 1;		/* Assert ODT on writes to CS0 */ +	} + +#ifdef CONFIG_DDR_INTERLEAVE + +	if (dimm_num != 1) { +		printf("For interleaving memory on HPCN, need to use DIMM 1 for DDR Controller %d !\n", ddr_num); +		return 0; +	} else { +		/* +		 * Since interleaved memory only uses CS0, the +		 * memory sticks have to be identical in size and quantity +		 * of ranks.  That essentially gives double the size on +		 * one rank, i.e on CS0 for both controllers put together. +		 * Confirm this??? +		 */ +		rank_density *= 2; + +		/* +		 * Eg: Bounds: 0x0000_0000 to 0x0f000_0000	first 256 Meg +		 */ +		start_addr = 0; +		ddr->cs0_bnds = (start_addr >> 8) +			| (((start_addr + rank_density - 1) >> 24)); +		/* +		 * Default interleaving mode to cache-line interleaving. +		 */ +		ddr->cs0_config = ( 1 << 31 +#if	(CFG_PAGE_INTERLEAVING == 1) +				    | (PAGE_INTERLEAVING) +#elif	(CFG_BANK_INTERLEAVING == 1) +				    | (BANK_INTERLEAVING) +#elif	(CFG_SUPER_BANK_INTERLEAVING == 1) +				    | (SUPER_BANK_INTERLEAVING) +#else +				    | (CACHE_LINE_INTERLEAVING) +#endif +				    | (odt_rd_cfg << 20) +				    | (odt_wr_cfg << 16) +				    | (spd.nrow_addr - 12) << 8 +				    | (spd.ncol_addr - 8) ); + +		debug("DDR: cs0_bnds   = 0x%08x\n", ddr->cs0_bnds); +		debug("DDR: cs0_config = 0x%08x\n", ddr->cs0_config); + +		/* +		 * Adjustment for dual rank memory to get correct memory +		 * size (return value of this function). +		 */ +		if (n_ranks == 2) { +			n_ranks = 1; +			rank_density /= 2; +		} else { +			rank_density /= 2; +		} +	} +#else	/* CONFIG_DDR_INTERLEAVE */ + +	if (dimm_num == 1) { +		/* +		 * Eg: Bounds: 0x0000_0000 to 0x0f000_0000	first 256 Meg +		 */ +		ddr->cs0_bnds = (start_addr >> 8) +			| (((start_addr + rank_density - 1) >> 24)); + +		ddr->cs0_config = ( 1 << 31 +				    | (odt_rd_cfg << 20) +				    | (odt_wr_cfg << 16) +				    | (spd.nrow_addr - 12) << 8 +				    | (spd.ncol_addr - 8) ); + +		debug("DDR: cs0_bnds   = 0x%08x\n", ddr->cs0_bnds); +		debug("DDR: cs0_config = 0x%08x\n", ddr->cs0_config); + +		if (n_ranks == 2) { +			/* +			 * Eg: Bounds: 0x1000_0000 to 0x1f00_0000, +			 * second 256 Meg +			 */ +			ddr->cs1_bnds = (((start_addr + rank_density) >> 8) +					| (( start_addr + 2*rank_density - 1) +					   >> 24)); +			ddr->cs1_config = ( 1<<31 +					    | (odt_rd_cfg << 20) +					    | (odt_wr_cfg << 16) +					    | (spd.nrow_addr - 12) << 8 +					    | (spd.ncol_addr - 8) ); +			debug("DDR: cs1_bnds   = 0x%08x\n", ddr->cs1_bnds); +			debug("DDR: cs1_config = 0x%08x\n", ddr->cs1_config); +		} + +	} else { +		/* +		 * This is the 2nd DIMM slot for this controller +		 */ +		/* +		 * Eg: Bounds: 0x0000_0000 to 0x0f000_0000	first 256 Meg +		 */ +		ddr->cs2_bnds = (start_addr >> 8) +			| (((start_addr + rank_density - 1) >> 24)); + +		ddr->cs2_config = ( 1 << 31 +				    | (odt_rd_cfg << 20) +				    | (odt_wr_cfg << 16) +				    | (spd.nrow_addr - 12) << 8 +				    | (spd.ncol_addr - 8) ); + +		debug("DDR: cs2_bnds   = 0x%08x\n", ddr->cs2_bnds); +		debug("DDR: cs2_config = 0x%08x\n", ddr->cs2_config); + +		if (n_ranks == 2) { +			/* +			 * Eg: Bounds: 0x1000_0000 to 0x1f00_0000, +			 * second 256 Meg +			 */ +			ddr->cs3_bnds = (((start_addr + rank_density) >> 8) +					| (( start_addr + 2*rank_density - 1) +					   >> 24)); +			ddr->cs3_config = ( 1<<31 +					    | (odt_rd_cfg << 20) +					    | (odt_wr_cfg << 16) +					    | (spd.nrow_addr - 12) << 8 +					    | (spd.ncol_addr - 8) ); +			debug("DDR: cs3_bnds   = 0x%08x\n", ddr->cs3_bnds); +			debug("DDR: cs3_config = 0x%08x\n", ddr->cs3_config); +		} +	} +#endif /* CONFIG_DDR_INTERLEAVE */ + +	/* +	 * Find the largest CAS by locating the highest 1 bit +	 * in the spd.cas_lat field.  Translate it to a DDR +	 * controller field value: +	 * +	 *	CAS Lat	DDR I	DDR II	Ctrl +	 *	Clocks	SPD Bit	SPD Bit	Value +	 *	-------	-------	-------	----- +	 *	1.0	0		0001 +	 *	1.5	1		0010 +	 *	2.0	2	2	0011 +	 *	2.5	3		0100 +	 *	3.0	4	3	0101 +	 *	3.5	5		0110 +	 *	4.0		4	0111 +	 *	4.5			1000 +	 *	5.0		5	1001 +	 */ +	caslat = __ilog2(spd.cas_lat); +	if ((spd.mem_type == SPD_MEMTYPE_DDR) +	    && (caslat > 5)) { +		printf("DDR I: Invalid SPD CAS Latency: 0x%x.\n", spd.cas_lat); +		return 0; + +	} else if (spd.mem_type == SPD_MEMTYPE_DDR2 +		   && (caslat < 2 || caslat > 5)) { +		printf("DDR II: Invalid SPD CAS Latency: 0x%x.\n", +		       spd.cas_lat); +		return 0; +	} +	debug("DDR: caslat SPD bit is %d\n", caslat); + +	/* +	 * Calculate the Maximum Data Rate based on the Minimum Cycle time. +	 * The SPD clk_cycle field (tCKmin) is measured in tenths of +	 * nanoseconds and represented as BCD. +	 */ +	tCKmin_ps = convert_bcd_tenths_to_cycle_time_ps(spd.clk_cycle); +	debug("DDR: tCKmin = %d ps\n", tCKmin_ps); + +	/* +	 * Double-data rate, scaled 1000 to picoseconds, and back down to MHz. +	 */ +	max_data_rate = 2 * 1000 * 1000 / tCKmin_ps; +	debug("DDR: Module max data rate = %d Mhz\n", max_data_rate); + + +	/* +	 * Adjust the CAS Latency to allow for bus speeds that +	 * are slower than the DDR module. +	 */ +	busfreq = get_bus_freq(0) / 1000000;	/* MHz */ +	tCycle_ps = convert_bcd_tenths_to_cycle_time_ps(spd.clk_cycle3); +	modfreq = 2 * 1000 * 1000 / tCycle_ps; + +	if ((spd.mem_type == SPD_MEMTYPE_DDR2) && (busfreq < 266)) { +		printf("DDR: platform frequency too low for correct DDR2 controller operation\n"); +		return 0; +	} else if (busfreq < 90) { +		printf("DDR: platform frequency too low for correct DDR1 operation\n"); +		return 0; +	} + +	if ((busfreq <= modfreq) && (spd.cas_lat & (1 << (caslat - 2)))) { +		caslat -= 2; +	} else { +		tCycle_ps = convert_bcd_tenths_to_cycle_time_ps(spd.clk_cycle2); +		modfreq = 2 * 1000 * 1000 / tCycle_ps; +		if ((busfreq <= modfreq) && (spd.cas_lat & (1 << (caslat - 1)))) +			caslat -= 1; +		else if (busfreq > max_data_rate) { +			printf("DDR: Bus freq %d MHz is not fit for DDR rate %d MHz\n", +		     	busfreq, max_data_rate); +			return 0; +		} +	} + +	/* +	 * Empirically set ~MCAS-to-preamble override for DDR 2. +	 * Your milage will vary. +	 */ +	cpo = 0; +	if (spd.mem_type == SPD_MEMTYPE_DDR2) { +		if (busfreq <= 333) { +			cpo = 0x7; +		} else if (busfreq <= 400) { +			cpo = 0x9; +		} else { +			cpo = 0xa; +		} +	} + +	/* +	 * Convert caslat clocks to DDR controller value. +	 * Force caslat_ctrl to be DDR Controller field-sized. +	 */ +	if (spd.mem_type == SPD_MEMTYPE_DDR) { +		caslat_ctrl = (caslat + 1) & 0x07; +	} else { +		caslat_ctrl =  (2 * caslat - 1) & 0x0f; +	} + +	debug("DDR: caslat SPD bit is %d, controller field is 0x%x\n", +	      caslat, caslat_ctrl); + +	/* +	 * Timing Config 0. +	 * Avoid writing for DDR I.  The new PQ38 DDR controller +	 * dreams up non-zero default values to be backwards compatible. +	 */ +	if (spd.mem_type == SPD_MEMTYPE_DDR2) { +		unsigned char taxpd_clk = 8;		/* By the book. */ +		unsigned char tmrd_clk = 2;		/* By the book. */ +		unsigned char act_pd_exit = 2;		/* Empirical? */ +		unsigned char pre_pd_exit = 6;		/* Empirical? */ + +		ddr->timing_cfg_0 = (0 +			| ((act_pd_exit & 0x7) << 20)	/* ACT_PD_EXIT */ +			| ((pre_pd_exit & 0x7) << 16)	/* PRE_PD_EXIT */ +			| ((taxpd_clk & 0xf) << 8)	/* ODT_PD_EXIT */ +			| ((tmrd_clk & 0xf) << 0)	/* MRS_CYC */ +			); +		debug("DDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0); + +	} + + +	/* +	 * Some Timing Config 1 values now. +	 * Sneak Extended Refresh Recovery in here too. +	 */ + +	/* +	 * For DDR I, WRREC(Twr) and WRTORD(Twtr) are not in SPD, +	 * use conservative value. +	 * For DDR II, they are bytes 36 and 37, in quarter nanos. +	 */ + +	if (spd.mem_type == SPD_MEMTYPE_DDR) { +		twr_clk = 3;	/* Clocks */ +		twtr_clk = 1;	/* Clocks */ +	} else { +		twr_clk = picos_to_clk(spd.twr * 250); +		twtr_clk = picos_to_clk(spd.twtr * 250); +	} + +	/* +	 * Calculate Trfc, in picos. +	 * DDR I:  Byte 42 straight up in ns. +	 * DDR II: Byte 40 and 42 swizzled some, in ns. +	 */ +	if (spd.mem_type == SPD_MEMTYPE_DDR) { +		trfc = spd.trfc * 1000;		/* up to ps */ +	} else { +		unsigned int byte40_table_ps[8] = { +			0, +			250, +			330, +			500, +			660, +			750, +			0, +			0 +		}; + +		trfc = (((spd.trctrfc_ext & 0x1) * 256) + spd.trfc) * 1000 +			+ byte40_table_ps[(spd.trctrfc_ext >> 1) & 0x7]; +	} +	trfc_clk = picos_to_clk(trfc); + +	/* +	 * Trcd, Byte 29, from quarter nanos to ps and clocks. +	 */ +	trcd_clk = picos_to_clk(spd.trcd * 250) & 0x7; + +	/* +	 * Convert trfc_clk to DDR controller fields.  DDR I should +	 * fit in the REFREC field (16-19) of TIMING_CFG_1, but the +	 * 8548 controller has an extended REFREC field of three bits. +	 * The controller automatically adds 8 clocks to this value, +	 * so preadjust it down 8 first before splitting it up. +	 */ +	trfc_low = (trfc_clk - 8) & 0xf; +	trfc_high = ((trfc_clk - 8) >> 4) & 0x3; + +	/* +	 * Sneak in some Extended Refresh Recovery. +	 */ +	ddr->ext_refrec = (trfc_high << 16); +	debug("DDR: ext_refrec = 0x%08x\n", ddr->ext_refrec); + +	ddr->timing_cfg_1 = +	    (0 +	     | ((picos_to_clk(spd.trp * 250) & 0x07) << 28)	/* PRETOACT */ +	     | ((picos_to_clk(spd.tras * 1000) & 0x0f ) << 24)	/* ACTTOPRE */ +	     | (trcd_clk << 20)					/* ACTTORW */ +	     | (caslat_ctrl << 16)				/* CASLAT */ +	     | (trfc_low << 12)					/* REFEC */ +	     | ((twr_clk & 0x07) << 8)				/* WRRREC */ +	     | ((picos_to_clk(spd.trrd * 250) & 0x07) << 4)	/* ACTTOACT */ +	     | ((twtr_clk & 0x07) << 0)				/* WRTORD */ +	     ); + +	debug("DDR: timing_cfg_1  = 0x%08x\n", ddr->timing_cfg_1); + + +	/* +	 * Timing_Config_2 +	 * Was: 0x00000800; +	 */ + +	/* +	 * Additive Latency +	 * For DDR I, 0. +	 * For DDR II, with ODT enabled, use "a value" less than ACTTORW, +	 * which comes from Trcd, and also note that: +	 *	add_lat + caslat must be >= 4 +	 */ +	add_lat = 0; +	if (spd.mem_type == SPD_MEMTYPE_DDR2 +	    && (odt_wr_cfg || odt_rd_cfg) +	    && (caslat < 4)) { +		add_lat = 4 - caslat; +		if (add_lat >= trcd_clk) { +			add_lat = trcd_clk - 1; +		} +	} + +	/* +	 * Write Data Delay +	 * Historically 0x2 == 4/8 clock delay. +	 * Empirically, 0x3 == 6/8 clock delay is suggested for DDR I 266. +	 */ +	wr_data_delay = 3; + +	/* +	 * Write Latency +	 * Read to Precharge +	 * Minimum CKE Pulse Width. +	 * Four Activate Window +	 */ +	if (spd.mem_type == SPD_MEMTYPE_DDR) { +		/* +		 * This is a lie.  It should really be 1, but if it is +		 * set to 1, bits overlap into the old controller's +		 * otherwise unused ACSM field.  If we leave it 0, then +		 * the HW will magically treat it as 1 for DDR 1.  Oh Yea. +		 */ +		wr_lat = 0; + +		trtp_clk = 2;		/* By the book. */ +		cke_min_clk = 1;	/* By the book. */ +		four_act = 1;		/* By the book. */ + +	} else { +		wr_lat = caslat - 1; + +		/* Convert SPD value from quarter nanos to picos. */ +		trtp_clk = picos_to_clk(spd.trtp * 250); + +		cke_min_clk = 3;	/* By the book. */ +		four_act = picos_to_clk(37500);	/* By the book. 1k pages? */ +	} + +	ddr->timing_cfg_2 = (0 +		| ((add_lat & 0x7) << 28)		/* ADD_LAT */ +		| ((cpo & 0x1f) << 23)			/* CPO */ +		| ((wr_lat & 0x7) << 19)		/* WR_LAT */ +		| ((trtp_clk & 0x7) << 13)		/* RD_TO_PRE */ +		| ((wr_data_delay & 0x7) << 10)		/* WR_DATA_DELAY */ +		| ((cke_min_clk & 0x7) << 6)		/* CKE_PLS */ +		| ((four_act & 0x1f) << 0)		/* FOUR_ACT */ +		); + +	debug("DDR: timing_cfg_2 = 0x%08x\n", ddr->timing_cfg_2); + + +	/* +	 * Determine the Mode Register Set. +	 * +	 * This is nominally part specific, but it appears to be +	 * consistent for all DDR I devices, and for all DDR II devices. +	 * +	 *     caslat must be programmed +	 *     burst length is always 4 +	 *     burst type is sequential +	 * +	 * For DDR I: +	 *     operating mode is "normal" +	 * +	 * For DDR II: +	 *     other stuff +	 */ + +	mode_caslat = 0; + +	/* +	 * Table lookup from DDR I or II Device Operation Specs. +	 */ +	if (spd.mem_type == SPD_MEMTYPE_DDR) { +		if (1 <= caslat && caslat <= 4) { +			unsigned char mode_caslat_table[4] = { +				0x5,	/* 1.5 clocks */ +				0x2,	/* 2.0 clocks */ +				0x6,	/* 2.5 clocks */ +				0x3	/* 3.0 clocks */ +			}; +			mode_caslat = mode_caslat_table[caslat - 1]; +		} else { +			puts("DDR I: Only CAS Latencies of 1.5, 2.0, " +			     "2.5 and 3.0 clocks are supported.\n"); +			return 0; +		} + +	} else { +		if (2 <= caslat && caslat <= 5) { +			mode_caslat = caslat; +		} else { +			puts("DDR II: Only CAS Latencies of 2.0, 3.0, " +			     "4.0 and 5.0 clocks are supported.\n"); +			return 0; +		} +	} + +	/* +	 * Encoded Burst Length of 4. +	 */ +	burst_len = 2;			/* Fiat. */ + +	if (spd.mem_type == SPD_MEMTYPE_DDR) { +		twr_auto_clk = 0;	/* Historical */ +	} else { +		/* +		 * Determine tCK max in picos.  Grab tWR and convert to picos. +		 * Auto-precharge write recovery is: +		 *	WR = roundup(tWR_ns/tCKmax_ns). +		 * +		 * Ponder: Is twr_auto_clk different than twr_clk? +		 */ +		tCKmax_ps = convert_bcd_tenths_to_cycle_time_ps(spd.tckmax); +		twr_auto_clk = (spd.twr * 250 + tCKmax_ps - 1) / tCKmax_ps; +	} + +	/* +	 * Mode Reg in bits 16 ~ 31, +	 * Extended Mode Reg 1 in bits 0 ~ 15. +	 */ +	mode_odt_enable = 0x0;			/* Default disabled */ +	if (odt_wr_cfg || odt_rd_cfg) { +		/* +		 * Bits 6 and 2 in Extended MRS(1) +		 * Bit 2 == 0x04 == 75 Ohm, with 2 DIMM modules. +		 * Bit 6 == 0x40 == 150 Ohm, with 1 DIMM module. +		 */ +		mode_odt_enable = 0x40;		/* 150 Ohm */ +	} + +	ddr->sdram_mode_1 = +		(0 +		 | (add_lat << (16 + 3))	/* Additive Latency in EMRS1 */ +		 | (mode_odt_enable << 16)	/* ODT Enable in EMRS1 */ +		 | (twr_auto_clk << 9)		/* Write Recovery Autopre */ +		 | (mode_caslat << 4)		/* caslat */ +		 | (burst_len << 0)		/* Burst length */ +		 ); + +	debug("DDR: sdram_mode   = 0x%08x\n", ddr->sdram_mode_1); + +	/* +	 * Clear EMRS2 and EMRS3. +	 */ +	ddr->sdram_mode_2 = 0; +	debug("DDR: sdram_mode_2 = 0x%08x\n", ddr->sdram_mode_2); + +	/* +	 * Determine Refresh Rate. +	 */ +	refresh_clk = determine_refresh_rate(spd.refresh & 0x7); + +	/* +	 * Set BSTOPRE to 0x100 for page mode +	 * If auto-charge is used, set BSTOPRE = 0 +	 */ +	ddr->sdram_interval = +		(0 +		 | (refresh_clk & 0x3fff) << 16 +		 | 0x100 +		 ); +	debug("DDR: sdram_interval = 0x%08x\n", ddr->sdram_interval); + + +	/* +	 * Is this an ECC DDR chip? +	 * But don't mess with it if the DDR controller will init mem. +	 */ +#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) +	if (spd.config == 0x02) { +		ddr->err_disable = 0x0000000d; +		ddr->err_sbe = 0x00ff0000; +	} +	debug("DDR: err_disable = 0x%08x\n", ddr->err_disable); +	debug("DDR: err_sbe = 0x%08x\n", ddr->err_sbe); +#endif + +	asm volatile("sync;isync"); +	udelay(500); + +	/* +	 * SDRAM Cfg 2 +	 */ + +	/* +	 * When ODT is enabled, Chap 9 suggests asserting ODT to +	 * internal IOs only during reads. +	 */ +	odt_cfg = 0; +	if (odt_rd_cfg | odt_wr_cfg) { +		odt_cfg = 0x2;		/* ODT to IOs during reads */ +	} + +	/* +	 * Try to use differential DQS with DDR II. +	 */ +	if (spd.mem_type == SPD_MEMTYPE_DDR) { +		dqs_cfg = 0;		/* No Differential DQS for DDR I */ +	} else { +		dqs_cfg = 0x1;		/* Differential DQS for DDR II */ +	} + +#if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) +	/* +	 * Use the DDR controller to auto initialize memory. +	 */ +	d_init = 1; +	ddr->sdram_data_init = CONFIG_MEM_INIT_VALUE; +	debug("DDR: ddr_data_init = 0x%08x\n", ddr->sdram_data_init); +#else +	/* +	 * Memory will be initialized via DMA, or not at all. +	 */ +	d_init = 0; +#endif + +	ddr->sdram_cfg_2 = (0 +			    | (dqs_cfg << 26)	/* Differential DQS */ +			    | (odt_cfg << 21)	/* ODT */ +			    | (d_init << 4)	/* D_INIT auto init DDR */ +			    ); + +	debug("DDR: sdram_cfg_2  = 0x%08x\n", ddr->sdram_cfg_2); + + +#ifdef MPC86xx_DDR_SDRAM_CLK_CNTL +	/* +	 * Setup the clock control. +	 * SDRAM_CLK_CNTL[0] = Source synchronous enable == 1 +	 * SDRAM_CLK_CNTL[5-7] = Clock Adjust +	 *	0110	3/4 cycle late +	 *	0111	7/8 cycle late +	 */ +	if (spd.mem_type == SPD_MEMTYPE_DDR) +		clk_adjust = 0x6; +	else +		clk_adjust = 0x7; + +	ddr->sdram_clk_cntl = (0 +			       | 0x80000000 +			       | (clk_adjust << 23) +			       ); +	debug("DDR: sdram_clk_cntl = 0x%08x\n", ddr->sdram_clk_cntl); +#endif + +	/* +	 * Figure out memory size in Megabytes. +	 */ +	debug("# ranks = %d, rank_density = 0x%08lx\n", n_ranks, rank_density); +	memsize = n_ranks * rank_density / 0x100000; +	return memsize; +} + + +unsigned int enable_ddr(unsigned int ddr_num) +{ +	volatile immap_t *immap = (immap_t *)CFG_IMMR; +	spd_eeprom_t spd1,spd2; +	volatile ccsr_ddr_t *ddr; +	unsigned sdram_cfg_1; +	unsigned char sdram_type, mem_type, config, mod_attr; +	unsigned char d_init; +	unsigned int no_dimm1=0, no_dimm2=0; + +	/* Set up pointer to enable the current ddr controller */ +	if (ddr_num == 1) +		ddr = &immap->im_ddr1; +	else +		ddr = &immap->im_ddr2; + +	/* +	 * Read both dimm slots and decide whether +	 * or not to enable this controller. +	 */ +	memset((void *)&spd1,0,sizeof(spd1)); +	memset((void *)&spd2,0,sizeof(spd2)); + +	if (ddr_num == 1) { +		CFG_READ_SPD(SPD_EEPROM_ADDRESS1, +			     0, 1, (uchar *) &spd1, sizeof(spd1)); +		CFG_READ_SPD(SPD_EEPROM_ADDRESS2, +			     0, 1, (uchar *) &spd2, sizeof(spd2)); +	} else { +		CFG_READ_SPD(SPD_EEPROM_ADDRESS3, +			     0, 1, (uchar *) &spd1, sizeof(spd1)); +		CFG_READ_SPD(SPD_EEPROM_ADDRESS4, +			     0, 1, (uchar *) &spd2, sizeof(spd2)); +	} + +	/* +	 * Check for supported memory module types. +	 */ +	if (spd1.mem_type != SPD_MEMTYPE_DDR +	    && spd1.mem_type != SPD_MEMTYPE_DDR2) { +		no_dimm1 = 1; +	} else { +		debug("\nFound memory of type 0x%02lx  ",spd1.mem_type ); +		if (spd1.mem_type == SPD_MEMTYPE_DDR) +			debug("DDR I\n"); +		else +			debug("DDR II\n"); +	} + +	if (spd2.mem_type != SPD_MEMTYPE_DDR && +	    spd2.mem_type != SPD_MEMTYPE_DDR2) { +		no_dimm2 = 1; +	} else { +		debug("\nFound memory of type 0x%02lx  ",spd2.mem_type ); +		if (spd2.mem_type == SPD_MEMTYPE_DDR) +			debug("DDR I\n"); +		else +			debug("DDR II\n"); +	} + +#ifdef CONFIG_DDR_INTERLEAVE +	if (no_dimm1) { +		printf("For interleaved operation memory modules need to be present in CS0 DIMM slots of both DDR controllers!\n"); +		return 0; +	} +#endif + +	/* +	 * Memory is not present in DIMM1 and DIMM2 - so do not enable DDRn +	 */ +	if (no_dimm1  && no_dimm2) { +		printf("No memory modules found for DDR controller %d!!\n", ddr_num); +		return 0; +	} else { +		mem_type = no_dimm2 ? spd1.mem_type : spd2.mem_type; + +		/* +		 * Figure out the settings for the sdram_cfg register. +		 * Build up the entire register in 'sdram_cfg' before +		 * writing since the write into the register will +		 * actually enable the memory controller; all settings +		 * must be done before enabling. +		 * +		 * sdram_cfg[0]   = 1 (ddr sdram logic enable) +		 * sdram_cfg[1]   = 1 (self-refresh-enable) +		 * sdram_cfg[5:7] = (SDRAM type = DDR SDRAM) +		 *			010 DDR 1 SDRAM +		 *			011 DDR 2 SDRAM +		 */ +		sdram_type = (mem_type == SPD_MEMTYPE_DDR) ? 2 : 3; +		sdram_cfg_1 = (0 +			       | (1 << 31)		/* Enable */ +			       | (1 << 30)		/* Self refresh */ +			       | (sdram_type << 24)	/* SDRAM type */ +			       ); + +		/* +		 * sdram_cfg[3] = RD_EN - registered DIMM enable +		 *   A value of 0x26 indicates micron registered +		 *   DIMMS (micron.com) +		 */ +		mod_attr = no_dimm2 ? spd1.mod_attr : spd2.mod_attr; +		if (mem_type == SPD_MEMTYPE_DDR && mod_attr == 0x26) { +			sdram_cfg_1 |= 0x10000000;		/* RD_EN */ +		} + +#if defined(CONFIG_DDR_ECC) + +		config = no_dimm2 ? spd1.config : spd2.config; + +		/* +		 * If the user wanted ECC (enabled via sdram_cfg[2]) +		 */ +		if (config == 0x02) { +			ddr->err_disable = 0x00000000; +			asm volatile("sync;isync;"); +			ddr->err_sbe = 0x00ff0000; +			ddr->err_int_en = 0x0000000d; +			sdram_cfg_1 |= 0x20000000;		/* ECC_EN */ +		} +#endif + +		/* +		 * Set 1T or 2T timing based on 1 or 2 modules +		 */ +		{ +			if (!(no_dimm1 || no_dimm2)) { +				/* +				 * 2T timing,because both DIMMS are present. +				 * Enable 2T timing by setting sdram_cfg[16]. +				 */ +				sdram_cfg_1 |= 0x8000;		/* 2T_EN */ +			} +		} + +		/* +		 * 200 painful micro-seconds must elapse between +		 * the DDR clock setup and the DDR config enable. +		 */ +		udelay(200); + +		/* +		 * Go! +		 */ +		ddr->sdram_cfg_1 = sdram_cfg_1; + +		asm volatile("sync;isync"); +		udelay(500); + +		debug("DDR: sdram_cfg   = 0x%08x\n", ddr->sdram_cfg_1); + + +#if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) +		d_init = 1; +		debug("DDR: memory initializing\n"); + +		/* +		 * Poll until memory is initialized. +		 * 512 Meg at 400 might hit this 200 times or so. +		 */ +		while ((ddr->sdram_cfg_2 & (d_init << 4)) != 0) { +			udelay(1000); +		} +		debug("DDR: memory initialized\n\n"); +#endif + +		debug("Enabled DDR Controller %d\n", ddr_num); +		return 1; +	} +} + + +long int +spd_sdram(void) +{ +	int memsize_ddr1_dimm1 = 0; +	int memsize_ddr1_dimm2 = 0; +	int memsize_ddr2_dimm1 = 0; +	int memsize_ddr2_dimm2 = 0; +	int memsize_total = 0; +	int memsize_ddr1 = 0; +	int memsize_ddr2 = 0; +	unsigned int ddr1_enabled = 0; +	unsigned int ddr2_enabled = 0; +	unsigned int law_size_ddr1; +	unsigned int law_size_ddr2; +	volatile immap_t *immap = (immap_t *)CFG_IMMR; +	volatile ccsr_local_mcm_t *mcm = &immap->im_local_mcm; + +#ifdef CONFIG_DDR_INTERLEAVE +	unsigned int law_size_interleaved; +	volatile ccsr_ddr_t *ddr1 = &immap->im_ddr1; +	volatile ccsr_ddr_t *ddr2 = &immap->im_ddr2; + +	memsize_ddr1_dimm1 = spd_init(SPD_EEPROM_ADDRESS1, +				      1, 1, +				      (unsigned int)memsize_total * 1024*1024); +	memsize_total += memsize_ddr1_dimm1; + +	memsize_ddr2_dimm1 = spd_init(SPD_EEPROM_ADDRESS3, +				      2, 1, +				      (unsigned int)memsize_total * 1024*1024); +	memsize_total += memsize_ddr2_dimm1; + +	if (memsize_ddr1_dimm1 != memsize_ddr2_dimm1) { +		if (memsize_ddr1_dimm1 <  memsize_ddr2_dimm1) +			memsize_total -= memsize_ddr1_dimm1; +		else +			memsize_total -= memsize_ddr2_dimm1; +		debug("Total memory available for interleaving 0x%08lx\n", +		      memsize_total * 1024 * 1024); +		debug("Adjusting CS0_BNDS to account for unequal DIMM sizes in interleaved memory\n"); +		ddr1->cs0_bnds = ((memsize_total * 1024 * 1024) - 1) >> 24; +		ddr2->cs0_bnds = ((memsize_total * 1024 * 1024) - 1) >> 24; +		debug("DDR1: cs0_bnds   = 0x%08x\n", ddr1->cs0_bnds); +		debug("DDR2: cs0_bnds   = 0x%08x\n", ddr2->cs0_bnds); +	} + +	ddr1_enabled = enable_ddr(1); +	ddr2_enabled = enable_ddr(2); + +	/* +	 * Both controllers need to be enabled for interleaving. +	 */ +	if (ddr1_enabled && ddr2_enabled) { +		law_size_interleaved = 19 + __ilog2(memsize_total); + +		/* +		 * Set up LAWBAR for DDR 1 space. +		 */ +		mcm->lawbar1 = ((CFG_DDR_SDRAM_BASE >> 12) & 0xfffff); +		mcm->lawar1 = (LAWAR_EN +			       | LAWAR_TRGT_IF_DDR_INTERLEAVED +			       | (LAWAR_SIZE & law_size_interleaved)); +		debug("DDR: LAWBAR1=0x%08x\n", mcm->lawbar1); +		debug("DDR: LAWAR1=0x%08x\n", mcm->lawar1); +		debug("Interleaved memory size is 0x%08lx\n", memsize_total); + +#ifdef	CONFIG_DDR_INTERLEAVE +#if (CFG_PAGE_INTERLEAVING == 1) +		printf("Page "); +#elif (CFG_BANK_INTERLEAVING == 1) +		printf("Bank "); +#elif (CFG_SUPER_BANK_INTERLEAVING == 1) +		printf("Super-bank "); +#else +		printf("Cache-line "); +#endif +#endif +		printf("Interleaved"); +		return memsize_total * 1024 * 1024; +	}  else { +		printf("Interleaved memory not enabled - check CS0 DIMM slots for both controllers.\n"); +		return 0; +	} + +#else +	/* +	 * Call spd_sdram() routine to init ddr1 - pass I2c address, +	 * controller number, dimm number, and starting address. +	 */ +	memsize_ddr1_dimm1 = spd_init(SPD_EEPROM_ADDRESS1, +				      1, 1, +				      (unsigned int)memsize_total * 1024*1024); +	memsize_total += memsize_ddr1_dimm1; + +	memsize_ddr1_dimm2 = spd_init(SPD_EEPROM_ADDRESS2, +				      1, 2, +				      (unsigned int)memsize_total * 1024*1024); +	memsize_total += memsize_ddr1_dimm2; + +	/* +	 * Enable the DDR controller - pass ddr controller number. +	 */ +	ddr1_enabled = enable_ddr(1); + +	/* Keep track of memory to be addressed by DDR1 */ +	memsize_ddr1 = memsize_ddr1_dimm1 + memsize_ddr1_dimm2; + +	/* +	 * First supported LAW size is 16M, at LAWAR_SIZE_16M == 23.  Fnord. +	 */ +	if (ddr1_enabled) { +		law_size_ddr1 = 19 + __ilog2(memsize_ddr1); + +		/* +		 * Set up LAWBAR for DDR 1 space. +		 */ +		mcm->lawbar1 = ((CFG_DDR_SDRAM_BASE >> 12) & 0xfffff); +		mcm->lawar1 = (LAWAR_EN +			       | LAWAR_TRGT_IF_DDR1 +			       | (LAWAR_SIZE & law_size_ddr1)); +		debug("DDR: LAWBAR1=0x%08x\n", mcm->lawbar1); +		debug("DDR: LAWAR1=0x%08x\n", mcm->lawar1); +	} + +#if  (CONFIG_NUM_DDR_CONTROLLERS > 1) +	memsize_ddr2_dimm1 = spd_init(SPD_EEPROM_ADDRESS3, +				      2, 1, +				      (unsigned int)memsize_total * 1024*1024); +	memsize_total += memsize_ddr2_dimm1; + +	memsize_ddr2_dimm2 = spd_init(SPD_EEPROM_ADDRESS4, +				      2, 2, +				      (unsigned int)memsize_total * 1024*1024); +	memsize_total += memsize_ddr2_dimm2; + +	ddr2_enabled = enable_ddr(2); + +	/* Keep track of memory to be addressed by DDR2 */ +	memsize_ddr2 = memsize_ddr2_dimm1 + memsize_ddr2_dimm2; + +	if (ddr2_enabled) { +		law_size_ddr2 = 19 + __ilog2(memsize_ddr2); + +		/* +		 * Set up LAWBAR for DDR 2 space. +		 */ +		if (ddr1_enabled) +			mcm->lawbar8 = (((memsize_ddr1 * 1024 * 1024) >> 12) +					& 0xfffff); +		else +			mcm->lawbar8 = ((CFG_DDR_SDRAM_BASE >> 12) & 0xfffff); + +		mcm->lawar8 = (LAWAR_EN +			       | LAWAR_TRGT_IF_DDR2 +			       | (LAWAR_SIZE & law_size_ddr2)); +		debug("\nDDR: LAWBAR8=0x%08x\n", mcm->lawbar8); +		debug("DDR: LAWAR8=0x%08x\n", mcm->lawar8); +	} +#endif /* CONFIG_NUM_DDR_CONTROLLERS > 1 */ + +	debug("\nMemory sizes are DDR1 = 0x%08lx, DDR2 = 0x%08lx\n", +	      memsize_ddr1, memsize_ddr2); + +	/* +	 * If neither DDR controller is enabled return 0. +	 */ +	if (!ddr1_enabled && !ddr2_enabled) +		return 0; + +	printf("Non-interleaved"); +	return memsize_total * 1024 * 1024; + +#endif /* CONFIG_DDR_INTERLEAVE */ +} + + +#endif /* CONFIG_SPD_EEPROM */ + + +#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) + +/* + * Initialize all of memory for ECC, then enable errors. + */ + +void +ddr_enable_ecc(unsigned int dram_size) +{ +	uint *p = 0; +	uint i = 0; +	volatile immap_t *immap = (immap_t *)CFG_IMMR; +	volatile ccsr_ddr_t *ddr1= &immap->im_ddr1; + +	dma_init(); + +	for (*p = 0; p < (uint *)(8 * 1024); p++) { +		if (((unsigned int)p & 0x1f) == 0) { +			ppcDcbz((unsigned long) p); +		} +		*p = (unsigned int)CONFIG_MEM_INIT_VALUE; +		if (((unsigned int)p & 0x1c) == 0x1c) { +			ppcDcbf((unsigned long) p); +		} +	} + +	dma_xfer((uint *)0x002000, 0x002000, (uint *)0); /* 8K */ +	dma_xfer((uint *)0x004000, 0x004000, (uint *)0); /* 16K */ +	dma_xfer((uint *)0x008000, 0x008000, (uint *)0); /* 32K */ +	dma_xfer((uint *)0x010000, 0x010000, (uint *)0); /* 64K */ +	dma_xfer((uint *)0x020000, 0x020000, (uint *)0); /* 128k */ +	dma_xfer((uint *)0x040000, 0x040000, (uint *)0); /* 256k */ +	dma_xfer((uint *)0x080000, 0x080000, (uint *)0); /* 512k */ +	dma_xfer((uint *)0x100000, 0x100000, (uint *)0); /* 1M */ +	dma_xfer((uint *)0x200000, 0x200000, (uint *)0); /* 2M */ +	dma_xfer((uint *)0x400000, 0x400000, (uint *)0); /* 4M */ + +	for (i = 1; i < dram_size / 0x800000; i++) { +		dma_xfer((uint *)(0x800000*i), 0x800000, (uint *)0); +	} + +	/* +	 * Enable errors for ECC. +	 */ +	debug("DMA DDR: err_disable = 0x%08x\n", ddr1->err_disable); +	ddr1->err_disable = 0x00000000; +	asm volatile("sync;isync"); +	debug("DMA DDR: err_disable = 0x%08x\n", ddr1->err_disable); +} + +#endif	/* CONFIG_DDR_ECC  && ! CONFIG_ECC_INIT_VIA_DDRCONTROLLER */ diff --git a/cpu/mpc86xx/speed.c b/cpu/mpc86xx/speed.c new file mode 100644 index 000000000..312ca1282 --- /dev/null +++ b/cpu/mpc86xx/speed.c @@ -0,0 +1,127 @@ +/* + * Copyright 2004 Freescale Semiconductor. + * Jeff Brown + * Srikanth Srinivasan (srikanth.srinivasan@freescale.com) + * + * (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 <common.h> +#include <mpc86xx.h> +#include <asm/processor.h> + + +void get_sys_info(sys_info_t *sysInfo) +{ +	volatile immap_t *immap = (immap_t *) CFG_IMMR; +	volatile ccsr_gur_t *gur = &immap->im_gur; +	uint plat_ratio, e600_ratio; + +	plat_ratio = (gur->porpllsr) & 0x0000003e; +	plat_ratio >>= 1; + +	switch (plat_ratio) { +	case 0x0: +		sysInfo->freqSystemBus = 16 * CONFIG_SYS_CLK_FREQ; +		break; +	case 0x02: +	case 0x03: +	case 0x04: +	case 0x05: +	case 0x06: +	case 0x08: +	case 0x09: +	case 0x0a: +	case 0x0c: +	case 0x10: +		sysInfo->freqSystemBus = plat_ratio * CONFIG_SYS_CLK_FREQ; +		break; +	default: +		sysInfo->freqSystemBus = 0; +		break; +	} + +	e600_ratio = (gur->porpllsr) & 0x003f0000; +	e600_ratio >>= 16; + +	switch (e600_ratio) { +	case 0x10: +		sysInfo->freqProcessor = 2 * sysInfo->freqSystemBus; +		break; +	case 0x19: +		sysInfo->freqProcessor = 5 * sysInfo->freqSystemBus / 2; +		break; +	case 0x20: +		sysInfo->freqProcessor = 3 * sysInfo->freqSystemBus; +		break; +	case 0x39: +		sysInfo->freqProcessor = 7 * sysInfo->freqSystemBus / 2; +		break; +	case 0x28: +		sysInfo->freqProcessor = 4 * sysInfo->freqSystemBus; +		break; +	case 0x1d: +		sysInfo->freqProcessor = 9 * sysInfo->freqSystemBus / 2; +		break; +	default: +		sysInfo->freqProcessor = e600_ratio + sysInfo->freqSystemBus; +		break; +	} +} + + +/* + * Measure CPU clock speed (core clock GCLK1, GCLK2) + * (Approx. GCLK frequency in Hz) + */ + +int get_clocks(void) +{ +	DECLARE_GLOBAL_DATA_PTR; +	sys_info_t sys_info; + +	get_sys_info(&sys_info); +	gd->cpu_clk = sys_info.freqProcessor; +	gd->bus_clk = sys_info.freqSystemBus; + +	if (gd->cpu_clk != 0) +		return 0; +	else +		return 1; +} + + +/* + * get_bus_freq + *	Return system bus freq in Hz + */ + +ulong get_bus_freq(ulong dummy) +{ +	ulong val; +	sys_info_t sys_info; + +	get_sys_info(&sys_info); +	val = sys_info.freqSystemBus; + +	return val; +} diff --git a/cpu/mpc86xx/start.S b/cpu/mpc86xx/start.S new file mode 100644 index 000000000..7406fe224 --- /dev/null +++ b/cpu/mpc86xx/start.S @@ -0,0 +1,1226 @@ +/* + * Copyright 2004 Freescale Semiconductor. + * Srikanth Srinivasan <srikanth.srinivaan@freescale.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/*  U-Boot - Startup Code for 86xx PowerPC based Embedded Boards + * + * + *  The processor starts at 0xfff00100 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. + */ +#include <config.h> +#include <mpc86xx.h> +#include <version.h> + +#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 +/* Machine Check and Recoverable Interr. */ +#define MSR_KERNEL ( MSR_ME | MSR_RI ) + +/* + * Set up GOT: Global Offset Table + * + * Use r14 to access the GOT + */ +	START_GOT +	GOT_ENTRY(_GOT2_TABLE_) +	GOT_ENTRY(_FIXUP_TABLE_) + +	GOT_ENTRY(_start) +	GOT_ENTRY(_start_of_vectors) +	GOT_ENTRY(_end_of_vectors) +	GOT_ENTRY(transfer_to_handler) + +	GOT_ENTRY(__init_end) +	GOT_ENTRY(_end) +	GOT_ENTRY(__bss_start) +	END_GOT + +/* + * r3 - 1st arg to board_init(): IMMP pointer + * r4 - 2nd arg to board_init(): boot flag + */ +	.text +	.long	0x27051956		/* U-Boot Magic Number */ +	.globl	version_string +version_string: +	.ascii	U_BOOT_VERSION +	.ascii	" (", __DATE__, " - ", __TIME__, ")" +	.ascii	CONFIG_IDENT_STRING, "\0" + +	. = EXC_OFF_SYS_RESET +	.globl	_start +_start: +	li	r21, BOOTFLAG_COLD	/* Normal Power-On: Boot from FLASH */ +	b	boot_cold +	sync + +	. = EXC_OFF_SYS_RESET + 0x10 + +	.globl	_start_warm +_start_warm: +	li	r21, BOOTFLAG_WARM	/* Software reboot */ +	b	boot_warm +	sync + +	/* the boot code is located below the exception table */ + +	.globl	_start_of_vectors +_start_of_vectors: + +/* Machine check */ +	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) + +/* Data Storage exception. */ +	STD_EXCEPTION(0x300, DataStorage, UnknownException) + +/* Instruction Storage exception. */ +	STD_EXCEPTION(0x400, InstStorage, UnknownException) + +/* External Interrupt exception. */ +	STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt) + +/* Alignment exception. */ +	. = 0x600 +Alignment: +	EXCEPTION_PROLOG +	mfspr	r4,DAR +	stw	r4,_DAR(r21) +	mfspr	r5,DSISR +	stw	r5,_DSISR(r21) +	addi	r3,r1,STACK_FRAME_OVERHEAD +	li	r20,MSR_KERNEL +	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */ +	lwz	r6,GOT(transfer_to_handler) +	mtlr	r6 +	blrl +.L_Alignment: +	.long	AlignmentException - _start + EXC_OFF_SYS_RESET +	.long	int_return - _start + EXC_OFF_SYS_RESET + +/* Program check exception */ +	. = 0x700 +ProgramCheck: +	EXCEPTION_PROLOG +	addi	r3,r1,STACK_FRAME_OVERHEAD +	li	r20,MSR_KERNEL +	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */ +	lwz	r6,GOT(transfer_to_handler) +	mtlr	r6 +	blrl +.L_ProgramCheck: +	.long	ProgramCheckException - _start + EXC_OFF_SYS_RESET +	.long	int_return - _start + EXC_OFF_SYS_RESET + +	STD_EXCEPTION(0x800, FPUnavailable, UnknownException) + +	/* I guess we could implement decrementer, and may have +	 * to someday for timekeeping. +	 */ +	STD_EXCEPTION(0x900, Decrementer, timer_interrupt) +	STD_EXCEPTION(0xa00, Trap_0a, UnknownException) +	STD_EXCEPTION(0xb00, Trap_0b, UnknownException) +	STD_EXCEPTION(0xc00, SystemCall, UnknownException) +	STD_EXCEPTION(0xd00, SingleStep, UnknownException) +	STD_EXCEPTION(0xe00, Trap_0e, UnknownException) +	STD_EXCEPTION(0xf00, Trap_0f, UnknownException) +	STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException) +	STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException) +	STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException) +	STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException) +	STD_EXCEPTION(0x1400, DataTLBError, 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, DataBreakpoint, UnknownException) +	STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException) +	STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException) +	STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException) + +	.globl	_end_of_vectors +_end_of_vectors: + +	. = 0x2000 + +boot_cold: +boot_warm: + +	/* if this is a multi-core system we need to check which cpu +	 * this is, if it is not cpu 0 send the cpu to the linux reset +	 * vector */ +#if (CONFIG_NUM_CPUS > 1) +	mfspr	r0, MSSCR0 +	andi.	r0, r0, 0x0020 +	rlwinm	r0,r0,27,31,31 +	mtspr	PIR, r0 +	beq	1f + +	bl	secondary_cpu_setup +#endif + +	/* disable everything */ +1:	li	r0, 0 +	mtspr	HID0, r0 +	sync +	mtmsr	0 +	bl	invalidate_bats +	sync + +#ifdef CFG_L2 +	/* init the L2 cache */ +	addis	r3, r0, L2_INIT@h +	ori	r3, r3, L2_INIT@l +	mtspr	l2cr, r3 +	/* invalidate the L2 cache */ +	bl	l2cache_invalidate +	sync +#endif + +	/* +	 * Calculate absolute address in FLASH and jump there +	 *------------------------------------------------------*/ +	lis	r3, CFG_MONITOR_BASE@h +	ori	r3, r3, CFG_MONITOR_BASE@l +	addi	r3, r3, in_flash - _start + EXC_OFF_SYS_RESET +	mtlr	r3 +	blr + +in_flash: +	/* let the C-code set up the rest			*/ +	/*							*/ +	/* Be careful to keep code relocatable !		*/ +	/*------------------------------------------------------*/ +	/* perform low-level init */ + +	/* enable extended addressing */ +	bl	enable_ext_addr + +	/* setup the bats */ +	bl	setup_bats +	sync + +#if (CFG_CCSRBAR_DEFAULT != CFG_CCSRBAR) +	/* setup ccsrbar */ +	bl	setup_ccsrbar +#endif + +	/* Fix for SMP linux - Changing arbitration to round-robin */ +	lis	r3, CFG_CCSRBAR@h +	ori	r3, r3, 0x1000 +	xor	r4, r4, r4 +	li	r4, 0x1000 +	stw	r4, 0(r3) + +	/* setup the law entries */ +	bl	law_entry +	sync + +	/* Don't use this feature due to bug in 8641D PD4 */ +	/* Disable ERD_DIS */ +	lis	r3, CFG_CCSRBAR@h +	ori	r3, r3, 0x1008 +	lwz	r4, 0(r3) +	oris	r4, r4, 0x4000 +	stw	r4, 0(r3) +	sync + +#if (EMULATOR_RUN == 1) +	/* On the emulator we want to adjust these ASAP */ +	/* otherwise things are sloooow */ +	/* Setup OR0 (LALE FIX)*/ +	lis	r3, CFG_CCSRBAR@h +	ori	r3, r3, 0x5004 +	li	r4, 0x0FF3 +	stw	r4, 0(r3) +	sync + +	/* Setup LCRR */ +	lis	r3, CFG_CCSRBAR@h +	ori	r3, r3, 0x50D4 +	lis	r4, 0x8000 +	ori	r4, r4, 0x0002 +	stw	r4, 0(r3) +	sync +#endif +#if 1 +	/* make sure timer enabled in guts register too */ +	lis	r3, CFG_CCSRBAR@h +	oris	r3,r3, 0xE +	ori	r3,r3,0x0070 +	lwz	r4, 0(r3) +	lis	r5,0xFFFC +	ori	r5,r5,0x5FFF +	and	r4,r4,r5 +	stw	r4,0(r3) +#endif +	/* +	 * Cache must be enabled here for stack-in-cache trick. +	 * This means we need to enable the BATS. +	 * Cache should be turned on after BATs, since by default +	 * everything is write-through. +	 */ + +	/* enable address translation */ +	bl	enable_addr_trans +	sync + +	/* enable and invalidate the data cache */ +/*	bl	l1dcache_enable */ +	bl	dcache_enable +	sync + +#if 1 +	bl	icache_enable +#endif + +#ifdef CFG_INIT_RAM_LOCK +	bl	lock_ram_in_cache +	sync +#endif + +	/* set up the stack pointer in our newly created +	 * cache-ram (r1) */ +	lis	r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@h +	ori	r1, r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@l + +	li	r0, 0		/* Make room for stack frame header and */ +	stwu	r0, -4(r1)	/* clear final stack frame so that	*/ +	stwu	r0, -4(r1)	/* stack backtraces terminate cleanly	*/ + +	GET_GOT			/* initialize GOT access	*/ + +	/* run low-level CPU init code	   (from Flash) */ +	bl	cpu_init_f +	sync + +#ifdef	RUN_DIAG + +	/* Sri:	 Code to run the diagnostic automatically */ + +	/* Load PX_AUX register address in r4 */ +	lis	r4, 0xf810 +	ori	r4, r4, 0x6 +	/* Load contents of PX_AUX in r3 bits 24 to 31*/ +	lbz	r3, 0(r4) + +	/* Mask and obtain the bit in r3 */ +	rlwinm. r3, r3, 0, 24, 24 +	/* If not zero, jump and continue with u-boot */ +	bne	diag_done + +	/* Load back contents of PX_AUX in r3 bits 24 to 31 */ +	lbz	r3, 0(r4) +	/* Set the MSB of the register value */ +	ori	r3, r3, 0x80 +	/* Write value in r3 back to PX_AUX */ +	stb	r3, 0(r4) + +	/* Get the address to jump to in r3*/ +	lis	r3, CFG_DIAG_ADDR@h +	ori	r3, r3, CFG_DIAG_ADDR@l + +	/* Load the LR with the branch address */ +	mtlr	r3 + +	/* Branch to diagnostic */ +	blr + +diag_done: +#endif + +/*	bl	l2cache_enable */ +	mr	r3, r21 + +	/* r3: BOOTFLAG */ +	/* run 1st part of board init code (from Flash)	  */ +	bl	board_init_f +	sync + +	/* NOTREACHED */ + +	.globl	invalidate_bats +invalidate_bats: + +	/* invalidate BATs */ +	mtspr	IBAT0U, r0 +	mtspr	IBAT1U, r0 +	mtspr	IBAT2U, r0 +	mtspr	IBAT3U, r0 +	mtspr	IBAT4U, r0 +	mtspr	IBAT5U, r0 +	mtspr	IBAT6U, r0 +	mtspr	IBAT7U, r0 + +	isync +	mtspr	DBAT0U, r0 +	mtspr	DBAT1U, r0 +	mtspr	DBAT2U, r0 +	mtspr	DBAT3U, r0 +	mtspr	DBAT4U, r0 +	mtspr	DBAT5U, r0 +	mtspr	DBAT6U, r0 +	mtspr	DBAT7U, r0 + +	isync +	sync +	blr + + +	/* setup_bats - set them up to some initial state */ +	.globl	setup_bats +setup_bats: + +	addis	r0, r0, 0x0000 + +	/* IBAT 0 */ +	addis	r4, r0, CFG_IBAT0L@h +	ori	r4, r4, CFG_IBAT0L@l +	addis	r3, r0, CFG_IBAT0U@h +	ori	r3, r3, CFG_IBAT0U@l +	mtspr	IBAT0L, r4 +	mtspr	IBAT0U, r3 +	isync + +	/* DBAT 0 */ +	addis	r4, r0, CFG_DBAT0L@h +	ori	r4, r4, CFG_DBAT0L@l +	addis	r3, r0, CFG_DBAT0U@h +	ori	r3, r3, CFG_DBAT0U@l +	mtspr	DBAT0L, r4 +	mtspr	DBAT0U, r3 +	isync + +	/* IBAT 1 */ +	addis	r4, r0, CFG_IBAT1L@h +	ori	r4, r4, CFG_IBAT1L@l +	addis	r3, r0, CFG_IBAT1U@h +	ori	r3, r3, CFG_IBAT1U@l +	mtspr	IBAT1L, r4 +	mtspr	IBAT1U, r3 +	isync + +	/* DBAT 1 */ +	addis	r4, r0, CFG_DBAT1L@h +	ori	r4, r4, CFG_DBAT1L@l +	addis	r3, r0, CFG_DBAT1U@h +	ori	r3, r3, CFG_DBAT1U@l +	mtspr	DBAT1L, r4 +	mtspr	DBAT1U, r3 +	isync + +	/* IBAT 2 */ +	addis	r4, r0, CFG_IBAT2L@h +	ori	r4, r4, CFG_IBAT2L@l +	addis	r3, r0, CFG_IBAT2U@h +	ori	r3, r3, CFG_IBAT2U@l +	mtspr	IBAT2L, r4 +	mtspr	IBAT2U, r3 +	isync + +	/* DBAT 2 */ +	addis	r4, r0, CFG_DBAT2L@h +	ori	r4, r4, CFG_DBAT2L@l +	addis	r3, r0, CFG_DBAT2U@h +	ori	r3, r3, CFG_DBAT2U@l +	mtspr	DBAT2L, r4 +	mtspr	DBAT2U, r3 +	isync + +	/* IBAT 3 */ +	addis	r4, r0, CFG_IBAT3L@h +	ori	r4, r4, CFG_IBAT3L@l +	addis	r3, r0, CFG_IBAT3U@h +	ori	r3, r3, CFG_IBAT3U@l +	mtspr	IBAT3L, r4 +	mtspr	IBAT3U, r3 +	isync + +	/* DBAT 3 */ +	addis	r4, r0, CFG_DBAT3L@h +	ori	r4, r4, CFG_DBAT3L@l +	addis	r3, r0, CFG_DBAT3U@h +	ori	r3, r3, CFG_DBAT3U@l +	mtspr	DBAT3L, r4 +	mtspr	DBAT3U, r3 +	isync + +	/* IBAT 4 */ +	addis	r4, r0, CFG_IBAT4L@h +	ori	r4, r4, CFG_IBAT4L@l +	addis	r3, r0, CFG_IBAT4U@h +	ori	r3, r3, CFG_IBAT4U@l +	mtspr	IBAT4L, r4 +	mtspr	IBAT4U, r3 +	isync + +	/* DBAT 4 */ +	addis	r4, r0, CFG_DBAT4L@h +	ori	r4, r4, CFG_DBAT4L@l +	addis	r3, r0, CFG_DBAT4U@h +	ori	r3, r3, CFG_DBAT4U@l +	mtspr	DBAT4L, r4 +	mtspr	DBAT4U, r3 +	isync + +	/* IBAT 5 */ +	addis	r4, r0, CFG_IBAT5L@h +	ori	r4, r4, CFG_IBAT5L@l +	addis	r3, r0, CFG_IBAT5U@h +	ori	r3, r3, CFG_IBAT5U@l +	mtspr	IBAT5L, r4 +	mtspr	IBAT5U, r3 +	isync + +	/* DBAT 5 */ +	addis	r4, r0, CFG_DBAT5L@h +	ori	r4, r4, CFG_DBAT5L@l +	addis	r3, r0, CFG_DBAT5U@h +	ori	r3, r3, CFG_DBAT5U@l +	mtspr	DBAT5L, r4 +	mtspr	DBAT5U, r3 +	isync + +	/* IBAT 6 */ +	addis	r4, r0, CFG_IBAT6L@h +	ori	r4, r4, CFG_IBAT6L@l +	addis	r3, r0, CFG_IBAT6U@h +	ori	r3, r3, CFG_IBAT6U@l +	mtspr	IBAT6L, r4 +	mtspr	IBAT6U, r3 +	isync + +	/* DBAT 6 */ +	addis	r4, r0, CFG_DBAT6L@h +	ori	r4, r4, CFG_DBAT6L@l +	addis	r3, r0, CFG_DBAT6U@h +	ori	r3, r3, CFG_DBAT6U@l +	mtspr	DBAT6L, r4 +	mtspr	DBAT6U, r3 +	isync + +	/* IBAT 7 */ +	addis	r4, r0, CFG_IBAT7L@h +	ori	r4, r4, CFG_IBAT7L@l +	addis	r3, r0, CFG_IBAT7U@h +	ori	r3, r3, CFG_IBAT7U@l +	mtspr	IBAT7L, r4 +	mtspr	IBAT7U, r3 +	isync + +	/* DBAT 7 */ +	addis	r4, r0, CFG_DBAT7L@h +	ori	r4, r4, CFG_DBAT7L@l +	addis	r3, r0, CFG_DBAT7U@h +	ori	r3, r3, CFG_DBAT7U@l +	mtspr	DBAT7L, r4 +	mtspr	DBAT7U, r3 +	isync + +1: +	addis	r3, 0, 0x0000 +	addis	r5, 0, 0x4	/* upper bound of 0x00040000 for 7400/750 */ +	isync + +tlblp: +	tlbie	r3 +	sync +	addi	r3, r3, 0x1000 +	cmp	0, 0, r3, r5 +	blt tlblp + +	blr + +	.globl enable_addr_trans +enable_addr_trans: +	/* enable address translation */ +	mfmsr	r5 +	ori	r5, r5, (MSR_IR | MSR_DR) +	mtmsr	r5 +	isync +	blr + +	.globl disable_addr_trans +disable_addr_trans: +	/* disable address translation */ +	mflr	r4 +	mfmsr	r3 +	andi.	r0, r3, (MSR_IR | MSR_DR) +	beqlr +	andc	r3, r3, r0 +	mtspr	SRR0, r4 +	mtspr	SRR1, r3 +	rfi + +/* + * This code finishes saving the registers to the exception frame + * and jumps to the appropriate handler for the exception. + * Register r21 is pointer into trap frame, r1 has new stack pointer. + */ +	.globl	transfer_to_handler +transfer_to_handler: +	stw	r22,_NIP(r21) +	lis	r22,MSR_POW@h +	andc	r23,r23,r22 +	stw	r23,_MSR(r21) +	SAVE_GPR(7, r21) +	SAVE_4GPRS(8, r21) +	SAVE_8GPRS(12, r21) +	SAVE_8GPRS(24, r21) +	mflr	r23 +	andi.	r24,r23,0x3f00		/* get vector offset */ +	stw	r24,TRAP(r21) +	li	r22,0 +	stw	r22,RESULT(r21) +	mtspr	SPRG2,r22		/* r1 is now kernel sp */ +	lwz	r24,0(r23)		/* virtual address of handler */ +	lwz	r23,4(r23)		/* where to go when done */ +	mtspr	SRR0,r24 +	mtspr	SRR1,r20 +	mtlr	r23 +	SYNC +	rfi				/* jump to handler, enable MMU */ + +int_return: +	mfmsr	r28		/* Disable interrupts */ +	li	r4,0 +	ori	r4,r4,MSR_EE +	andc	r28,r28,r4 +	SYNC			/* Some chip revs need this... */ +	mtmsr	r28 +	SYNC +	lwz	r2,_CTR(r1) +	lwz	r0,_LINK(r1) +	mtctr	r2 +	mtlr	r0 +	lwz	r2,_XER(r1) +	lwz	r0,_CCR(r1) +	mtspr	XER,r2 +	mtcrf	0xFF,r0 +	REST_10GPRS(3, r1) +	REST_10GPRS(13, r1) +	REST_8GPRS(23, r1) +	REST_GPR(31, r1) +	lwz	r2,_NIP(r1)	/* Restore environment */ +	lwz	r0,_MSR(r1) +	mtspr	SRR0,r2 +	mtspr	SRR1,r0 +	lwz	r0,GPR0(r1) +	lwz	r2,GPR2(r1) +	lwz	r1,GPR1(r1) +	SYNC +	rfi + +	.globl	dc_read +dc_read: +	blr + +	.globl get_pvr +get_pvr: +	mfspr	r3, PVR +	blr + +	.globl get_svr +get_svr: +	mfspr	r3, SVR +	blr + + +/* + * Function:	in8 + * Description:	Input 8 bits + */ +	.globl	in8 +in8: +	lbz	r3,0x0000(r3) +	blr + +/* + * Function:	out8 + * Description:	Output 8 bits + */ +	.globl	out8 +out8: +	stb	r4,0x0000(r3) +	blr + +/* + * Function:	out16 + * Description:	Output 16 bits + */ +	.globl	out16 +out16: +	sth	r4,0x0000(r3) +	blr + +/* + * Function:	out16r + * Description:	Byte reverse and output 16 bits + */ +	.globl	out16r +out16r: +	sthbrx	r4,r0,r3 +	blr + +/* + * Function:	out32 + * Description:	Output 32 bits + */ +	.globl	out32 +out32: +	stw	r4,0x0000(r3) +	blr + +/* + * Function:	out32r + * Description:	Byte reverse and output 32 bits + */ +	.globl	out32r +out32r: +	stwbrx	r4,r0,r3 +	blr + +/* + * Function:	in16 + * Description:	Input 16 bits + */ +	.globl	in16 +in16: +	lhz	r3,0x0000(r3) +	blr + +/* + * Function:	in16r + * Description:	Input 16 bits and byte reverse + */ +	.globl	in16r +in16r: +	lhbrx	r3,r0,r3 +	blr + +/* + * Function:	in32 + * Description:	Input 32 bits + */ +	.globl	in32 +in32: +	lwz	3,0x0000(3) +	blr + +/* + * Function:	in32r + * Description:	Input 32 bits and byte reverse + */ +	.globl	in32r +in32r: +	lwbrx	r3,r0,r3 +	blr + +/* + * Function:	ppcDcbf + * Description:	Data Cache block flush + * Input:	r3 = effective address + * Output:	none. + */ +	.globl	ppcDcbf +ppcDcbf: +	dcbf	r0,r3 +	blr + +/* + * Function:	ppcDcbi + * Description:	Data Cache block Invalidate + * Input:	r3 = effective address + * Output:	none. + */ +	.globl	ppcDcbi +ppcDcbi: +	dcbi	r0,r3 +	blr + +/* + * Function:	ppcDcbz + * Description:	Data Cache block zero. + * Input:	r3 = effective address + * Output:	none. + */ +	.globl	ppcDcbz +ppcDcbz: +	dcbz	r0,r3 +	blr + +/* + * Function:	ppcSync + * Description:	Processor Synchronize + * Input:	none. + * Output:	none. + */ +	.globl	ppcSync +ppcSync: +	sync +	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	r29, r9		/* Save for DECLARE_GLOBAL_DATA_PTR	*/ +	mr	r10, r5		/* Save copy of Destination Address	*/ + +	mr	r3,  r5				/* Destination Address	*/ +	lis	r4, CFG_MONITOR_BASE@h		/* Source      Address	*/ +	ori	r4, r4, CFG_MONITOR_BASE@l +	lwz	r5, GOT(__init_end) +	sub	r5, r5, r4 +	li	r6, CFG_CACHELINE_SIZE		/* Cache Line Size	*/ + +	/* +	 * Fix GOT pointer: +	 * +	 * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address +	 * +	 * Offset: +	 */ +	sub	r15, r10, r4 + +	/* First our own GOT */ +	add	r14, r14, r15 +	/* then the one used by the C code */ +	add	r30, r30, r15 + +	/* +	 * Now relocate code +	 */ +#ifdef CONFIG_ECC +	bl	board_relocate_rom +	sync +	mr	r3, r10				/* Destination Address	*/ +	lis	r4, CFG_MONITOR_BASE@h		/* Source      Address	*/ +	ori	r4, r4, CFG_MONITOR_BASE@l +	lwz	r5, GOT(__init_end) +	sub	r5, r5, r4 +	li	r6, CFG_CACHELINE_SIZE		/* Cache Line Size	*/ +#else +	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 +#endif +/* + * Now flush the cache: note that we must start from a cache aligned + * address. Otherwise we might miss one cache line. + */ +4:	cmpwi	r6,0 +	add	r5,r3,r5 +	beq	7f		/* Always flush prefetch queue in any case */ +	subi	r0,r6,1 +	andc	r3,r3,r0 +	mr	r4,r3 +5:	dcbst	0,r4 +	add	r4,r4,r6 +	cmplw	r4,r5 +	blt	5b +	sync			/* Wait for all dcbst to complete on bus */ +	mr	r4,r3 +6:	icbi	0,r4 +	add	r4,r4,r6 +	cmplw	r4,r5 +	blt	6b +7:	sync			/* Wait for all icbi to complete on bus */ +	isync + +/* + * We are done. Do not return, instead branch to second part of board + * initialization, now running from RAM. + */ +	addi	r0, r10, in_ram - _start + EXC_OFF_SYS_RESET +	mtlr	r0 +	blr + +in_ram: +#ifdef CONFIG_ECC +	bl	board_init_ecc +#endif +	/* +	 * Relocation Function, r14 point to got2+0x8000 +	 * +	 * Adjust got2 pointers, no need to check for 0, this code +	 * already puts a few entries in the table. +	 */ +	li	r0,__got2_entries@sectoff@l +	la	r3,GOT(_GOT2_TABLE_) +	lwz	r11,GOT(_GOT2_TABLE_) +	mtctr	r0 +	sub	r11,r3,r11 +	addi	r3,r3,-4 +1:	lwzu	r0,4(r3) +	add	r0,r0,r11 +	stw	r0,0(r3) +	bdnz	1b + +	/* +	 * Now adjust the fixups and the pointers to the fixups +	 * in case we need to move ourselves again. +	 */ +2:	li	r0,__fixup_entries@sectoff@l +	lwz	r3,GOT(_FIXUP_TABLE_) +	cmpwi	r0,0 +	mtctr	r0 +	addi	r3,r3,-4 +	beq	4f +3:	lwzu	r4,4(r3) +	lwzux	r0,r4,r11 +	add	r0,r0,r11 +	stw	r10,0(r3) +	stw	r0,0(r4) +	bdnz	3b +4: +/* clear_bss: */ +	/* +	 * Now clear BSS segment +	 */ +	lwz	r3,GOT(__bss_start) +	lwz	r4,GOT(_end) + +	cmplw	0, r3, r4 +	beq	6f + +	li	r0, 0 +5: +	stw	r0, 0(r3) +	addi	r3, r3, 4 +	cmplw	0, r3, r4 +	bne	5b +6: +	mr	r3, r9		/* Init Date pointer		*/ +	mr	r4, r10		/* Destination Address		*/ +	bl	board_init_r + +	/* not reached - end relocate_code */ +/*-----------------------------------------------------------------------*/ + +	/* +	 * Copy exception vector code to low memory +	 * +	 * r3: dest_addr +	 * r7: source address, r8: end address, r9: target address +	 */ +	.globl	trap_init +trap_init: +	lwz	r7, GOT(_start) +	lwz	r8, GOT(_end_of_vectors) + +	li	r9, 0x100		/* reset vector always at 0x100 */ + +	cmplw	0, r7, r8 +	bgelr				/* return if r7>=r8 - just in case */ + +	mflr	r4			/* save link register		*/ +1: +	lwz	r0, 0(r7) +	stw	r0, 0(r9) +	addi	r7, r7, 4 +	addi	r9, r9, 4 +	cmplw	0, r7, r8 +	bne	1b + +	/* +	 * relocate `hdlr' and `int_return' entries +	 */ +	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET +	li	r8, Alignment - _start + EXC_OFF_SYS_RESET +2: +	bl	trap_reloc +	addi	r7, r7, 0x100		/* next exception vector	*/ +	cmplw	0, r7, r8 +	blt	2b + +	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET +	bl	trap_reloc + +	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET +	bl	trap_reloc + +	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET +	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET +3: +	bl	trap_reloc +	addi	r7, r7, 0x100		/* next exception vector	*/ +	cmplw	0, r7, r8 +	blt	3b + +	li	r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET +	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET +4: +	bl	trap_reloc +	addi	r7, r7, 0x100		/* next exception vector	*/ +	cmplw	0, r7, r8 +	blt	4b + +	/* enable execptions from RAM vectors */ +	mfmsr	r7 +	li	r8,MSR_IP +	andc	r7,r7,r8 +	mtmsr	r7 + +	mtlr	r4			/* restore link register	*/ +	blr + +	/* +	 * Function: relocate entries for one exception vector +	 */ +trap_reloc: +	lwz	r0, 0(r7)		/* hdlr ...			*/ +	add	r0, r0, r3		/*  ... += dest_addr		*/ +	stw	r0, 0(r7) + +	lwz	r0, 4(r7)		/* int_return ...		*/ +	add	r0, r0, r3		/*  ... += dest_addr		*/ +	stw	r0, 4(r7) + +	sync +	isync + +	blr + +.globl enable_ext_addr +enable_ext_addr: +	mfspr	r0, HID0 +	lis	r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@h +	ori	r0, r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@l +	mtspr	HID0, r0 +	sync +	isync +	blr + +#if (CFG_CCSRBAR_DEFAULT != CFG_CCSRBAR) +.globl setup_ccsrbar +setup_ccsrbar: +	/* Special sequence needed to update CCSRBAR itself */ +	lis	r4, CFG_CCSRBAR_DEFAULT@h +	ori	r4, r4, CFG_CCSRBAR_DEFAULT@l + +	lis	r5, CFG_CCSRBAR@h +	ori	r5, r5, CFG_CCSRBAR@l +	srwi	r6,r5,12 +	stw	r6, 0(r4) +	isync + +	lis	r5, 0xffff +	ori	r5,r5,0xf000 +	lwz	r5, 0(r5) +	isync + +	lis	r3, CFG_CCSRBAR@h +	lwz	r5, CFG_CCSRBAR@l(r3) +	isync + +	blr +#endif + +#ifdef CFG_INIT_RAM_LOCK +lock_ram_in_cache: +	/* Allocate Initial RAM in data cache. +	 */ +	lis	r3, (CFG_INIT_RAM_ADDR & ~31)@h +	ori	r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l +	li	r2, ((CFG_INIT_RAM_END & ~31) + \ +		     (CFG_INIT_RAM_ADDR & 31) + 31) / 32 +	mtctr	r2 +1: +	dcbz	r0, r3 +	addi	r3, r3, 32 +	bdnz	1b +#if 1 +/* Lock the data cache */ +	mfspr	r0, HID0 +	ori	r0, r0, 0x1000 +	sync +	mtspr	HID0, r0 +	sync +	blr +#endif +#if 0 +	/* Lock the first way of the data cache */ +	mfspr	r0, LDSTCR +	ori	r0, r0, 0x0080 +#if defined(CONFIG_ALTIVEC) +	dssall +#endif +	sync +	mtspr	LDSTCR, r0 +	sync +	isync +	blr +#endif + +.globl unlock_ram_in_cache +unlock_ram_in_cache: +	/* invalidate the INIT_RAM section */ +	lis	r3, (CFG_INIT_RAM_ADDR & ~31)@h +	ori	r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l +	li	r2, ((CFG_INIT_RAM_END & ~31) + \ +		     (CFG_INIT_RAM_ADDR & 31) + 31) / 32 +	mtctr	r2 +1:	icbi	r0, r3 +	addi	r3, r3, 32 +	bdnz	1b +	sync			/* Wait for all icbi to complete on bus */ +	isync +#if 1 +/* Unlock the data cache and invalidate it */ +	mfspr	r0, HID0 +	li	r3,0x1000 +	andc	r0,r0,r3 +	li	r3,0x0400 +	or	r0,r0,r3 +	sync +	mtspr	HID0, r0 +	sync +	blr +#endif +#if 0 +	/* Unlock the first way of the data cache */ +	mfspr	r0, LDSTCR +	li	r3,0x0080 +	andc	r0,r0,r3 +#ifdef CONFIG_ALTIVEC +	dssall +#endif +	sync +	mtspr	LDSTCR, r0 +	sync +	isync +	li	r3,0x0400 +	or	r0,r0,r3 +	sync +	mtspr	HID0, r0 +	sync +	blr +#endif +#endif + +/* If this is a multi-cpu system then we need to handle the + * 2nd cpu.  The assumption is that the 2nd cpu is being + * held in boot holdoff mode until the 1st cpu unlocks it + * from Linux.	We'll do some basic cpu init and then pass + * it to the Linux Reset Vector. + * Sri:	 Much of this initialization is not required. Linux + * rewrites the bats, and the sprs and also enables the L1 cache. + */ +#if (CONFIG_NUM_CPUS > 1) +.globl secondary_cpu_setup +secondary_cpu_setup: +	/* Do only core setup on all cores except cpu0 */ +	bl	invalidate_bats +	sync +	bl	enable_ext_addr + +#ifdef CFG_L2 +	/* init the L2 cache */ +	addis	r3, r0, L2_INIT@h +	ori	r3, r3, L2_INIT@l +	sync +	mtspr	l2cr, r3 +#ifdef CONFIG_ALTIVEC +	dssall +#endif +	/* invalidate the L2 cache */ +	bl	l2cache_invalidate +	sync +#endif + +	/* enable and invalidate the data cache */ +	bl	dcache_enable +	sync + +	/* enable and invalidate the instruction cache*/ +	bl	icache_enable +	sync + +	/* TBEN in HID0 */ +	mfspr	r4, HID0 +	oris	r4, r4, 0x0400 +	mtspr	HID0, r4 +	sync +	isync + +	/*SYNCBE|ABE in HID1*/ +	mfspr	r4, HID1 +	ori	r4, r4, 0x0C00 +	mtspr	HID1, r4 +	sync +	isync + +	lis	r3, CONFIG_LINUX_RESET_VEC@h +	ori	r3, r3, CONFIG_LINUX_RESET_VEC@l +	mtlr	r3 +	blr + +	/* Never Returns, Running in Linux Now */ +#endif diff --git a/cpu/mpc86xx/traps.c b/cpu/mpc86xx/traps.c new file mode 100644 index 000000000..8ea14e575 --- /dev/null +++ b/cpu/mpc86xx/traps.c @@ -0,0 +1,226 @@ +/* + * 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 <command.h> +#include <asm/processor.h> + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +int (*debugger_exception_handler)(struct pt_regs *) = 0; +#endif + +/* Returns 0 if exception not found and fixup otherwise.  */ +extern unsigned long search_exception_table(unsigned long); + +#define END_OF_MEM (gd->bd->bi_memstart + gd->bd->bi_memsize) + +/* + * Trap & Exception support + */ + +void +print_backtrace(unsigned long *sp) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	int cnt = 0; +	unsigned long i; + +	printf("Call backtrace: "); +	while (sp) { +		if ((uint) sp > END_OF_MEM) +			break; + +		i = sp[1]; +		if (cnt++ % 7 == 0) +			printf("\n"); +		printf("%08lX ", i); +		if (cnt > 32) +			break; +		sp = (unsigned long *)*sp; +	} +	printf("\n"); +} + +void +show_regs(struct pt_regs *regs) +{ +	int i; + +	printf("NIP: %08lX XER: %08lX LR: %08lX REGS:" +	       " %p TRAP: %04lx DAR: %08lX\n", +	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar); +	printf("MSR: %08lx EE: %01x PR: %01x FP:" +	       " %01x ME: %01x IR/DR: %01x%01x\n", +	       regs->msr, regs->msr & MSR_EE ? 1 : 0, +	       regs->msr & MSR_PR ? 1 : 0, regs->msr & MSR_FP ? 1 : 0, +	       regs->msr & MSR_ME ? 1 : 0, regs->msr & MSR_IR ? 1 : 0, +	       regs->msr & MSR_DR ? 1 : 0); + +	printf("\n"); +	for (i = 0; i < 32; i++) { +		if ((i % 8) == 0) { +			printf("GPR%02d: ", i); +		} + +		printf("%08lX ", regs->gpr[i]); +		if ((i % 8) == 7) { +			printf("\n"); +		} +	} +} + + +void +_exception(int signr, struct pt_regs *regs) +{ +	show_regs(regs); +	print_backtrace((unsigned long *)regs->gpr[1]); +	panic("Exception in kernel pc %lx signal %d", regs->nip, signr); +} + +void +MachineCheckException(struct pt_regs *regs) +{ +	unsigned long fixup; + +	/* Probing PCI using config cycles cause this exception +	 * when a device is not present.  Catch it and return to +	 * the PCI exception handler. +	 */ +	if ((fixup = search_exception_table(regs->nip)) != 0) { +		regs->nip = fixup; +		return; +	} + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +	if (debugger_exception_handler && (*debugger_exception_handler) (regs)) +		return; +#endif + +	printf("Machine check in kernel mode.\n"); +	printf("Caused by (from msr): "); +	printf("regs %p ", regs); +	switch (regs->msr & 0x000F0000) { +	case (0x80000000 >> 12): +		printf("Machine check signal - probably due to mm fault\n" +		       "with mmu off\n"); +		break; +	case (0x80000000 >> 13): +		printf("Transfer error ack signal\n"); +		break; +	case (0x80000000 >> 14): +		printf("Data parity signal\n"); +		break; +	case (0x80000000 >> 15): +		printf("Address parity signal\n"); +		break; +	default: +		printf("Unknown values in msr\n"); +	} +	show_regs(regs); +	print_backtrace((unsigned long *)regs->gpr[1]); +	panic("machine check"); +} + +void +AlignmentException(struct pt_regs *regs) +{ +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +	if (debugger_exception_handler && (*debugger_exception_handler) (regs)) +		return; +#endif +	show_regs(regs); +	print_backtrace((unsigned long *)regs->gpr[1]); +	panic("Alignment Exception"); +} + +void +ProgramCheckException(struct pt_regs *regs) +{ +	unsigned char *p = regs ? (unsigned char *)(regs->nip) : NULL; +	int i, j; + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +	if (debugger_exception_handler && (*debugger_exception_handler) (regs)) +		return; +#endif +	show_regs(regs); + +	p = (unsigned char *)((unsigned long)p & 0xFFFFFFE0); +	p -= 32; +	for (i = 0; i < 256; i += 16) { +		printf("%08x: ", (unsigned int)p + i); +		for (j = 0; j < 16; j++) { +			printf("%02x ", p[i + j]); +		} +		printf("\n"); +	} + +	print_backtrace((unsigned long *)regs->gpr[1]); +	panic("Program Check Exception"); +} + +void +SoftEmuException(struct pt_regs *regs) +{ +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +	if (debugger_exception_handler && (*debugger_exception_handler) (regs)) +		return; +#endif +	show_regs(regs); +	print_backtrace((unsigned long *)regs->gpr[1]); +	panic("Software Emulation Exception"); +} + +void +UnknownException(struct pt_regs *regs) +{ +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +	if (debugger_exception_handler && (*debugger_exception_handler) (regs)) +		return; +#endif +	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", +	       regs->nip, regs->msr, regs->trap); +	_exception(0, regs); +} + +/* + * Probe an address by reading. + * If not present, return -1, + * otherwise return 0. + */ +int +addr_probe(uint *addr) +{ +	return 0; +} diff --git a/cpu/mpc8xx/Makefile b/cpu/mpc8xx/Makefile index 6451e0551..223b30cbc 100644 --- a/cpu/mpc8xx/Makefile +++ b/cpu/mpc8xx/Makefile @@ -41,7 +41,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) $(obj)kgdb.o +	$(AR) $(ARFLAGS) $@ $(OBJS) $(obj)kgdb.o  ######################################################################### diff --git a/cpu/nios/Makefile b/cpu/nios/Makefile index cdab7b008..ad1745608 100644 --- a/cpu/nios/Makefile +++ b/cpu/nios/Makefile @@ -36,7 +36,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/nios2/Makefile b/cpu/nios2/Makefile index f90312959..75f30b43a 100644 --- a/cpu/nios2/Makefile +++ b/cpu/nios2/Makefile @@ -36,7 +36,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/ppc4xx/Makefile b/cpu/ppc4xx/Makefile index 16dc8d62c..baecf7035 100644 --- a/cpu/ppc4xx/Makefile +++ b/cpu/ppc4xx/Makefile @@ -41,7 +41,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/ppc4xx/cpu.c b/cpu/ppc4xx/cpu.c index 4e81ce240..faa525750 100644 --- a/cpu/ppc4xx/cpu.c +++ b/cpu/ppc4xx/cpu.c @@ -196,6 +196,7 @@ int checkcpu (void)  	char buf[32];  #if !defined(CONFIG_IOP480) +	char addstr[64] = "";  	sys_info_t sys_info;  	puts ("CPU:   "); @@ -312,19 +313,23 @@ int checkcpu (void)  #endif /* CONFIG_440 */  	case PVR_440EPX1_RA: -		puts("EPx Rev. A - Security/Kasumi support"); +		puts("EPx Rev. A"); +		strcpy(addstr, "Security/Kasumi support");  		break;  	case PVR_440EPX2_RA: -		puts("EPx Rev. A - No Security/Kasumi support"); +		puts("EPx Rev. A"); +		strcpy(addstr, "No Security/Kasumi support");  		break;  	case PVR_440GRX1_RA: -		puts("GRx Rev. A - Security/Kasumi support"); +		puts("GRx Rev. A"); +		strcpy(addstr, "Security/Kasumi support");  		break;  	case PVR_440GRX2_RA: -		puts("GRx Rev. A - No Security/Kasumi support"); +		puts("GRx Rev. A"); +		strcpy(addstr, "No Security/Kasumi support");  		break;  	case PVR_440SP_RA: @@ -353,13 +358,16 @@ int checkcpu (void)  	       sys_info.freqPLB / sys_info.pllOpbDiv / 1000000,  	       FREQ_EBC / 1000000); +	if (addstr[0] != 0) +		printf("       %s\n", addstr); +  #if defined(I2C_BOOTROM)  	printf ("       I2C boot EEPROM %sabled\n", i2c_bootrom_enabled() ? "en" : "dis");  #if defined(SDR0_PINSTP_SHIFT)  	printf ("       Bootstrap Option %c - ", (char)bootstrap_option() + 'A');  	printf ("Boot ROM Location %s\n", bootstrap_str[bootstrap_option()]); -#endif -#endif +#endif	/* SDR0_PINSTP_SHIFT */ +#endif	/* I2C_BOOTROM */  #if defined(CONFIG_PCI)  	printf ("       Internal PCI arbiter %sabled", pci_arbiter_enabled() ? "en" : "dis"); diff --git a/cpu/ppc4xx/cpu_init.c b/cpu/ppc4xx/cpu_init.c index b27567fa4..def46f15c 100644 --- a/cpu/ppc4xx/cpu_init.c +++ b/cpu/ppc4xx/cpu_init.c @@ -226,13 +226,19 @@ cpu_init_f (void)  	/*  	 * GPIO0 setup (select GPIO or alternate function)  	 */ -	out32(GPIO0_OSRH, CFG_GPIO0_OSRH);   /* output select */ +#if defined(CFG_GPIO0_OR) +	out32(GPIO0_OR, CFG_GPIO0_OR);		/* set initial state of output pins	*/ +#endif +#if defined(CFG_GPIO0_ODR) +	out32(GPIO0_ODR, CFG_GPIO0_ODR);	/* open-drain select			*/ +#endif +	out32(GPIO0_OSRH, CFG_GPIO0_OSRH);	/* output select			*/  	out32(GPIO0_OSRL, CFG_GPIO0_OSRL); -	out32(GPIO0_ISR1H, CFG_GPIO0_ISR1H); /* input select */ +	out32(GPIO0_ISR1H, CFG_GPIO0_ISR1H);	/* input select				*/  	out32(GPIO0_ISR1L, CFG_GPIO0_ISR1L); -	out32(GPIO0_TSRH, CFG_GPIO0_TSRH);   /* three-state select */ +	out32(GPIO0_TSRH, CFG_GPIO0_TSRH);	/* three-state select			*/  	out32(GPIO0_TSRL, CFG_GPIO0_TSRL); -	out32(GPIO0_TCR, CFG_GPIO0_TCR);     /* enable output driver for outputs */ +	out32(GPIO0_TCR, CFG_GPIO0_TCR);	/* enable output driver for outputs	*/  	/*  	 * Set EMAC noise filter bits diff --git a/cpu/ppc4xx/ndfc.c b/cpu/ppc4xx/ndfc.c index c255f93e6..352173128 100644 --- a/cpu/ppc4xx/ndfc.c +++ b/cpu/ppc4xx/ndfc.c @@ -65,8 +65,8 @@ static void ndfc_hwcontrol(struct mtd_info *mtdinfo, int cmd)  static void ndfc_write_byte(struct mtd_info *mtdinfo, u_char byte)  { -        struct nand_chip *this = mtdinfo->priv; -        ulong base = (ulong) this->IO_ADDR_W; +	struct nand_chip *this = mtdinfo->priv; +	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;  	if (hwctl & 0x1)  		out8(base + NDFC_CMD, byte); @@ -78,16 +78,16 @@ static void ndfc_write_byte(struct mtd_info *mtdinfo, u_char byte)  static u_char ndfc_read_byte(struct mtd_info *mtdinfo)  { -        struct nand_chip *this = mtdinfo->priv; -        ulong base = (ulong) this->IO_ADDR_W; +	struct nand_chip *this = mtdinfo->priv; +	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;  	return (in8(base + NDFC_DATA));  }  static int ndfc_dev_ready(struct mtd_info *mtdinfo)  { -        struct nand_chip *this = mtdinfo->priv; -        ulong base = (ulong) this->IO_ADDR_W; +	struct nand_chip *this = mtdinfo->priv; +	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;  	while (!(in32(base + NDFC_STAT) & NDFC_STAT_IS_READY))  		; @@ -110,31 +110,31 @@ static int ndfc_dev_ready(struct mtd_info *mtdinfo)   */  static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len)  { -        struct nand_chip *this = mtdinfo->priv; -        ulong base = (ulong) this->IO_ADDR_W; +	struct nand_chip *this = mtdinfo->priv; +	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;  	uint32_t *p = (uint32_t *) buf; -	for(;len > 0; len -= 4) +	for (;len > 0; len -= 4)  		*p++ = in32(base + NDFC_DATA);  }  static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)  { -        struct nand_chip *this = mtdinfo->priv; -        ulong base = (ulong) this->IO_ADDR_W; +	struct nand_chip *this = mtdinfo->priv; +	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;  	uint32_t *p = (uint32_t *) buf; -	for(; len > 0; len -= 4) +	for (; len > 0; len -= 4)  		out32(base + NDFC_DATA, *p++);  }  static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)  { -        struct nand_chip *this = mtdinfo->priv; -        ulong base = (ulong) this->IO_ADDR_W; +	struct nand_chip *this = mtdinfo->priv; +	ulong base = (ulong) this->IO_ADDR_W & 0xfffffffc;  	uint32_t *p = (uint32_t *) buf; -	for(; len > 0; len -= 4) +	for (; len > 0; len -= 4)  		if (*p++ != in32(base + NDFC_DATA))  			return -1; @@ -142,8 +142,25 @@ static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len  }  #endif /* #ifndef CONFIG_NAND_SPL */ +void board_nand_select_device(struct nand_chip *nand, int chip) +{ +	/* +	 * Don't use "chip" to address the NAND device, +	 * generate the cs from the address where it is encoded. +	 */ +	int cs = (ulong)nand->IO_ADDR_W & 0x00000003; +	ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc; + +	/* Set NandFlash Core Configuration Register */ +	/* 1col x 2 rows */ +	out32(base + NDFC_CCR, 0x00000000 | (cs << 24)); +} +  void board_nand_init(struct nand_chip *nand)  { +	int cs = (ulong)nand->IO_ADDR_W & 0x00000003; +	ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc; +  	nand->eccmode = NAND_ECC_SOFT;  	nand->hwcontrol  = ndfc_hwcontrol; @@ -166,10 +183,11 @@ void board_nand_init(struct nand_chip *nand)  	mtebc(pb0ap, CFG_EBC_PB0AP);  #endif -	/* Set NandFlash Core Configuration Register */ -	/* Chip select 3, 1col x 2 rows */ -	out32(CFG_NAND_BASE + NDFC_CCR, 0x00000000 | (CFG_NAND_CS << 24)); -	out32(CFG_NAND_BASE + NDFC_BCFG0 + (CFG_NAND_CS << 2), 0x80002222); +	/* +	 * Select required NAND chip in NDFC +	 */ +	board_nand_select_device(nand, cs); +	out32(base + NDFC_BCFG0 + (cs << 2), 0x80002222);  }  #endif diff --git a/cpu/ppc4xx/start.S b/cpu/ppc4xx/start.S index 5a1ab386b..3fe13daaf 100644 --- a/cpu/ppc4xx/start.S +++ b/cpu/ppc4xx/start.S @@ -173,9 +173,9 @@  /**************************************************************************/  _start_440: -        /*--------------------------------------------------------------------+ -        | 440EPX BUP Change - Hardware team request -        +--------------------------------------------------------------------*/ +	/*--------------------------------------------------------------------+ +	| 440EPX BUP Change - Hardware team request +	+--------------------------------------------------------------------*/  #if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)  	sync  	nop @@ -1697,7 +1697,8 @@ ppc405ep_init:  	mtdcr	ebccfgd,r3  #endif -	addi	r3,0,CPC0_PCI_HOST_CFG_EN +#ifndef CFG_CPC0_PCI +	li	r3,CPC0_PCI_HOST_CFG_EN  #ifdef CONFIG_BUBINGA  	/*  	!----------------------------------------------------------------------- @@ -1712,6 +1713,9 @@ ppc405ep_init:  	beq	..pci_cfg_set		  /* if not set, then bypass reg write*/  #endif  	ori	r3,r3,CPC0_PCI_ARBIT_EN +#else /* CFG_CPC0_PCI */ +	li	r3,CFG_CPC0_PCI +#endif /* CFG_CPC0_PCI */  ..pci_cfg_set:  	mtdcr	CPC0_PCI, r3		 /* Enable internal arbiter*/ diff --git a/cpu/pxa/Makefile b/cpu/pxa/Makefile index a6f6b599a..cded7ffd3 100644 --- a/cpu/pxa/Makefile +++ b/cpu/pxa/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/s3c44b0/Makefile b/cpu/s3c44b0/Makefile index 62cb51411..790faebd3 100644 --- a/cpu/s3c44b0/Makefile +++ b/cpu/s3c44b0/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  ######################################################################### diff --git a/cpu/sa1100/Makefile b/cpu/sa1100/Makefile index 62cb51411..790faebd3 100644 --- a/cpu/sa1100/Makefile +++ b/cpu/sa1100/Makefile @@ -35,7 +35,7 @@ START	:= $(addprefix $(obj),$(START))  all:	$(obj).depend $(START) $(LIB)  $(LIB):	$(OBJS) -	$(AR) crv $@ $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS)  #########################################################################  |