diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc85xx')
29 files changed, 6492 insertions, 0 deletions
| diff --git a/arch/powerpc/cpu/mpc85xx/Makefile b/arch/powerpc/cpu/mpc85xx/Makefile new file mode 100644 index 000000000..f064fee26 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/Makefile @@ -0,0 +1,95 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2002,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 $(TOPDIR)/config.mk + +LIB	= $(obj)lib$(CPU).a + +START	= start.o resetvec.o +SOBJS-$(CONFIG_MP)	+= release.o +SOBJS	= $(SOBJS-y) + +COBJS-$(CONFIG_CPM2)	+= commproc.o + +# supports ddr1 +COBJS-$(CONFIG_MPC8540) += ddr-gen1.o +COBJS-$(CONFIG_MPC8560) += ddr-gen1.o +COBJS-$(CONFIG_MPC8541) += ddr-gen1.o +COBJS-$(CONFIG_MPC8555) += ddr-gen1.o + +# supports ddr1/2 +COBJS-$(CONFIG_MPC8548) += ddr-gen2.o +COBJS-$(CONFIG_MPC8568) += ddr-gen2.o +COBJS-$(CONFIG_MPC8544) += ddr-gen2.o + +# supports ddr1/2/3 +COBJS-$(CONFIG_MPC8572) += ddr-gen3.o +COBJS-$(CONFIG_MPC8536) += ddr-gen3.o +COBJS-$(CONFIG_MPC8569)	+= ddr-gen3.o +COBJS-$(CONFIG_P1011)	+= ddr-gen3.o +COBJS-$(CONFIG_P1012)	+= ddr-gen3.o +COBJS-$(CONFIG_P1013)	+= ddr-gen3.o +COBJS-$(CONFIG_P1020)	+= ddr-gen3.o +COBJS-$(CONFIG_P1021)	+= ddr-gen3.o +COBJS-$(CONFIG_P1022)	+= ddr-gen3.o +COBJS-$(CONFIG_P2010)	+= ddr-gen3.o +COBJS-$(CONFIG_P2020)	+= ddr-gen3.o +COBJS-$(CONFIG_PPC_P4080)	+= ddr-gen3.o + +COBJS-$(CONFIG_CPM2)	+= ether_fcc.o +COBJS-$(CONFIG_OF_LIBFDT) += fdt.o +COBJS-$(CONFIG_MP)	+= mp.o +COBJS-$(CONFIG_MPC8536) += mpc8536_serdes.o +COBJS-$(CONFIG_PCI)	+= pci.o +COBJS-$(CONFIG_QE)	+= qe_io.o +COBJS-$(CONFIG_CPM2)	+= serial_scc.o + +COBJS	= $(COBJS-y) +COBJS	+= cpu.o +COBJS	+= cpu_init.o +COBJS	+= cpu_init_early.o +COBJS	+= interrupts.o +COBJS	+= speed.o +COBJS	+= tlb.o +COBJS	+= traps.o + +SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) +START	:= $(addprefix $(obj),$(START)) + +all:	$(obj).depend $(START) $(LIB) + +$(LIB):	$(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/powerpc/cpu/mpc85xx/commproc.c b/arch/powerpc/cpu/mpc85xx/commproc.c new file mode 100644 index 000000000..f0fd1cbc3 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/commproc.c @@ -0,0 +1,205 @@ +/* + * Adapted for Motorola MPC8560 chips + * Xianghua Xiao <x.xiao@motorola.com> + * + * This file is based on "arch/powerpc/8260_io/commproc.c" - here is it's + * copyright notice: + * + * General Purpose functions for the global management of the + * 8220 Communication Processor Module. + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) + * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com) + *	2.3.99 Updates + * Copyright (c) 2003 Motorola,Inc. + * + * In addition to the individual control of the communication + * channels, there are a few functions that globally affect the + * communication processor. + * + * Buffer descriptors must be allocated from the dual ported memory + * space.  The allocator for that is here.  When the communication + * process is reset, we reclaim the memory available.  There is + * currently no deallocator for this memory. + */ +#include <common.h> +#include <asm/cpm_85xx.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * because we have stack and init data in dual port ram + * we must reduce the size + */ +#undef	CPM_DATAONLY_SIZE +#define CPM_DATAONLY_SIZE	((uint)(8 * 1024) - CPM_DATAONLY_BASE) + +void +m8560_cpm_reset(void) +{ +	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; +	volatile ulong count; + +	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET); + +	/* Reclaim the DP memory for our use. +	*/ +	gd->dp_alloc_base = CPM_DATAONLY_BASE; +	gd->dp_alloc_top = gd->dp_alloc_base + CPM_DATAONLY_SIZE; + +	/* +	 * Reset CPM +	 */ +	cpm->im_cpm_cp.cpcr = CPM_CR_RST; +	count = 0; +	do {			/* Spin until command processed		*/ +		__asm__ __volatile__ ("eieio"); +	} while ((cpm->im_cpm_cp.cpcr & CPM_CR_FLG) && ++count < 1000000); +} + +/* Allocate some memory from the dual ported ram. + * To help protocols with object alignment restrictions, we do that + * if they ask. + */ +uint +m8560_cpm_dpalloc(uint size, uint align) +{ +	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; +	uint	retloc; +	uint	align_mask, off; +	uint	savebase; + +	align_mask = align - 1; +	savebase = gd->dp_alloc_base; + +	if ((off = (gd->dp_alloc_base & align_mask)) != 0) +		gd->dp_alloc_base += (align - off); + +	if ((off = size & align_mask) != 0) +		size += align - off; + +	if ((gd->dp_alloc_base + size) >= gd->dp_alloc_top) { +		gd->dp_alloc_base = savebase; +		panic("m8560_cpm_dpalloc: ran out of dual port ram!"); +	} + +	retloc = gd->dp_alloc_base; +	gd->dp_alloc_base += size; + +	memset((void *)&(cpm->im_dprambase[retloc]), 0, size); + +	return(retloc); +} + +/* We also own one page of host buffer space for the allocation of + * UART "fifos" and the like. + */ +uint +m8560_cpm_hostalloc(uint size, uint align) +{ +	/* the host might not even have RAM yet - just use dual port RAM */ +	return (m8560_cpm_dpalloc(size, align)); +} + +/* Set a baud rate generator.  This needs lots of work.  There are + * eight BRGs, which can be connected to the CPM channels or output + * as clocks.  The BRGs are in two different block of internal + * memory mapped space. + * The baud rate clock is the system clock divided by something. + * It was set up long ago during the initial boot phase and is + * is given to us. + * Baud rate clocks are zero-based in the driver code (as that maps + * to port numbers).  Documentation uses 1-based numbering. + */ +#define BRG_INT_CLK	gd->brg_clk +#define BRG_UART_CLK	((BRG_INT_CLK + 15) / 16) + +/* This function is used by UARTS, or anything else that uses a 16x + * oversampled clock. + */ +void +m8560_cpm_setbrg(uint brg, uint rate) +{ +	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; +	volatile uint	*bp; + +	/* This is good enough to get SMCs running..... +	*/ +	if (brg < 4) { +		bp = (uint *)&(cpm->im_cpm_brg1.brgc1); +	} +	else { +		bp = (uint *)&(cpm->im_cpm_brg2.brgc5); +		brg -= 4; +	} +	bp += brg; +	*bp = (((((BRG_UART_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN; +} + +/* This function is used to set high speed synchronous baud rate + * clocks. + */ +void +m8560_cpm_fastbrg(uint brg, uint rate, int div16) +{ +	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; +	volatile uint	*bp; + +	/* This is good enough to get SMCs running..... +	*/ +	if (brg < 4) { +		bp = (uint *)&(cpm->im_cpm_brg1.brgc1); +	} +	else { +		bp = (uint *)&(cpm->im_cpm_brg2.brgc5); +		brg -= 4; +	} +	bp += brg; +	*bp = (((((BRG_INT_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN; +	if (div16) +		*bp |= CPM_BRG_DIV16; +} + +/* This function is used to set baud rate generators using an external + * clock source and 16x oversampling. + */ + +void +m8560_cpm_extcbrg(uint brg, uint rate, uint extclk, int pinsel) +{ +	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; +	volatile uint	*bp; + +	if (brg < 4) { +		bp = (uint *)&(cpm->im_cpm_brg1.brgc1); +	} +	else { +		bp = (uint *)&(cpm->im_cpm_brg2.brgc5); +		brg -= 4; +	} +	bp += brg; +	*bp = ((((((extclk/16)+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN; +	if (pinsel == 0) +		*bp |= CPM_BRG_EXTC_CLK3_9; +	else +		*bp |= CPM_BRG_EXTC_CLK5_15; +} + +#ifdef CONFIG_POST + +void post_word_store (ulong a) +{ +	volatile ulong *save_addr = +		(volatile ulong *)(CONFIG_SYS_IMMR + CPM_POST_WORD_ADDR); + +	*save_addr = a; +} + +ulong post_word_load (void) +{ +	volatile ulong *save_addr = +		(volatile ulong *)(CONFIG_SYS_IMMR + CPM_POST_WORD_ADDR); + +	return *save_addr; +} + +#endif	/* CONFIG_POST */ diff --git a/arch/powerpc/cpu/mpc85xx/config.mk b/arch/powerpc/cpu/mpc85xx/config.mk new file mode 100644 index 000000000..f07d9209a --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/config.mk @@ -0,0 +1,35 @@ +# +# (C) Copyright 2002,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 +# + +PLATFORM_RELFLAGS += -fPIC -meabi + +PLATFORM_CPPFLAGS += -ffixed-r2 -Wa,-me500 -msoft-float -mno-string + +# -mspe=yes is needed to have -mno-spe accepted by a buggy GCC; +# see "[PATCH,rs6000] make -mno-spe work as expected" on +# http://gcc.gnu.org/ml/gcc-patches/2008-04/msg00311.html +PLATFORM_CPPFLAGS +=$(call cc-option,-mspe=yes) +PLATFORM_CPPFLAGS +=$(call cc-option,-mno-spe) + +# Use default linker script.  Board port can override in board/*/config.mk +LDSCRIPT := $(SRCTREE)/arch/powerpc/cpu/mpc85xx/u-boot.lds diff --git a/arch/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c new file mode 100644 index 000000000..0cc6e0323 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/cpu.c @@ -0,0 +1,330 @@ +/* + * Copyright 2004,2007-2009 Freescale Semiconductor, Inc. + * (C) Copyright 2002, 2003 Motorola Inc. + * Xianghua Xiao (X.Xiao@motorola.com) + * + * (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 + */ + +#include <config.h> +#include <common.h> +#include <watchdog.h> +#include <command.h> +#include <fsl_esdhc.h> +#include <asm/cache.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +int checkcpu (void) +{ +	sys_info_t sysinfo; +	uint pvr, svr; +	uint fam; +	uint ver; +	uint major, minor; +	struct cpu_type *cpu; +	char buf1[32], buf2[32]; +#ifdef CONFIG_DDR_CLK_FREQ +	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +#ifdef CONFIG_FSL_CORENET +	u32 ddr_sync = ((gur->rcwsr[5]) & FSL_CORENET_RCWSR5_DDR_SYNC) +		>> FSL_CORENET_RCWSR5_DDR_SYNC_SHIFT; +#else +	u32 ddr_ratio = ((gur->porpllsr) & MPC85xx_PORPLLSR_DDR_RATIO) +		>> MPC85xx_PORPLLSR_DDR_RATIO_SHIFT; +#endif +#else +#ifdef CONFIG_FSL_CORENET +	u32 ddr_sync = 0; +#else +	u32 ddr_ratio = 0; +#endif +#endif /* CONFIG_DDR_CLK_FREQ */ +	int i; + +	svr = get_svr(); +	major = SVR_MAJ(svr); +#ifdef CONFIG_MPC8536 +	major &= 0x7; /* the msb of this nibble is a mfg code */ +#endif +	minor = SVR_MIN(svr); + +	if (cpu_numcores() > 1) { +#ifndef CONFIG_MP +		puts("Unicore software on multiprocessor system!!\n" +		     "To enable mutlticore build define CONFIG_MP\n"); +#endif +		volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR); +		printf("CPU%d:  ", pic->whoami); +	} else { +		puts("CPU:   "); +	} + +	cpu = gd->cpu; + +	puts(cpu->name); +	if (IS_E_PROCESSOR(svr)) +		puts("E"); + +	printf(", Version: %d.%d, (0x%08x)\n", major, minor, svr); + +	pvr = get_pvr(); +	fam = PVR_FAM(pvr); +	ver = PVR_VER(pvr); +	major = PVR_MAJ(pvr); +	minor = PVR_MIN(pvr); + +	printf("Core:  "); +	switch (fam) { +	case PVR_FAM(PVR_85xx): +	    puts("E500"); +	    break; +	default: +	    puts("Unknown"); +	    break; +	} + +	if (PVR_MEM(pvr) == 0x03) +		puts("MC"); + +	printf(", Version: %d.%d, (0x%08x)\n", major, minor, pvr); + +	get_sys_info(&sysinfo); + +	puts("Clock Configuration:"); +	for (i = 0; i < cpu_numcores(); i++) { +		if (!(i & 3)) +			printf ("\n       "); +		printf("CPU%d:%-4s MHz, ", +				i,strmhz(buf1, sysinfo.freqProcessor[i])); +	} +	printf("\n       CCB:%-4s MHz,\n", strmhz(buf1, sysinfo.freqSystemBus)); + +#ifdef CONFIG_FSL_CORENET +	if (ddr_sync == 1) { +		printf("       DDR:%-4s MHz (%s MT/s data rate) " +			"(Synchronous), ", +			strmhz(buf1, sysinfo.freqDDRBus/2), +			strmhz(buf2, sysinfo.freqDDRBus)); +	} else { +		printf("       DDR:%-4s MHz (%s MT/s data rate) " +			"(Asynchronous), ", +			strmhz(buf1, sysinfo.freqDDRBus/2), +			strmhz(buf2, sysinfo.freqDDRBus)); +	} +#else +	switch (ddr_ratio) { +	case 0x0: +		printf("       DDR:%-4s MHz (%s MT/s data rate), ", +			strmhz(buf1, sysinfo.freqDDRBus/2), +			strmhz(buf2, sysinfo.freqDDRBus)); +		break; +	case 0x7: +		printf("       DDR:%-4s MHz (%s MT/s data rate) " +			"(Synchronous), ", +			strmhz(buf1, sysinfo.freqDDRBus/2), +			strmhz(buf2, sysinfo.freqDDRBus)); +		break; +	default: +		printf("       DDR:%-4s MHz (%s MT/s data rate) " +			"(Asynchronous), ", +			strmhz(buf1, sysinfo.freqDDRBus/2), +			strmhz(buf2, sysinfo.freqDDRBus)); +		break; +	} +#endif + +	if (sysinfo.freqLocalBus > LCRR_CLKDIV) { +		printf("LBC:%-4s MHz\n", strmhz(buf1, sysinfo.freqLocalBus)); +	} else { +		printf("LBC: unknown (LCRR[CLKDIV] = 0x%02lx)\n", +		       sysinfo.freqLocalBus); +	} + +#ifdef CONFIG_CPM2 +	printf("CPM:   %s MHz\n", strmhz(buf1, sysinfo.freqSystemBus)); +#endif + +#ifdef CONFIG_QE +	printf("       QE:%-4s MHz\n", strmhz(buf1, sysinfo.freqQE)); +#endif + +#ifdef CONFIG_SYS_DPAA_FMAN +	for (i = 0; i < CONFIG_SYS_NUM_FMAN; i++) { +		printf("       FMAN%d: %s MHz\n", i, +			strmhz(buf1, sysinfo.freqFMan[i])); +	} +#endif + +#ifdef CONFIG_SYS_DPAA_PME +	printf("       PME:   %s MHz\n", strmhz(buf1, sysinfo.freqPME)); +#endif + +	puts("L1:    D-cache 32 kB enabled\n       I-cache 32 kB enabled\n"); + +	return 0; +} + + +/* ------------------------------------------------------------------------- */ + +int do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]) +{ +/* Everything after the first generation of PQ3 parts has RSTCR */ +#if defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ +    defined(CONFIG_MPC8555) || defined(CONFIG_MPC8560) +	unsigned long val, msr; + +	/* +	 * Initiate hard reset in debug control register DBCR0 +	 * Make sure MSR[DE] = 1.  This only resets the core. +	 */ +	msr = mfmsr (); +	msr |= MSR_DE; +	mtmsr (msr); + +	val = mfspr(DBCR0); +	val |= 0x70000000; +	mtspr(DBCR0,val); +#else +	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +	out_be32(&gur->rstcr, 0x2);	/* HRESET_REQ */ +	udelay(100); +#endif + +	return 1; +} + + +/* + * Get timebase clock frequency + */ +unsigned long get_tbclk (void) +{ +#ifdef CONFIG_FSL_CORENET +	return (gd->bus_clk + 8) / 16; +#else +	return (gd->bus_clk + 4UL)/8UL; +#endif +} + + +#if defined(CONFIG_WATCHDOG) +void +watchdog_reset(void) +{ +	int re_enable = disable_interrupts(); +	reset_85xx_watchdog(); +	if (re_enable) enable_interrupts(); +} + +void +reset_85xx_watchdog(void) +{ +	/* +	 * Clear TSR(WIS) bit by writing 1 +	 */ +	unsigned long val; +	val = mfspr(SPRN_TSR); +	val |= TSR_WIS; +	mtspr(SPRN_TSR, val); +} +#endif	/* CONFIG_WATCHDOG */ + +/* + * Configures a UPM. The function requires the respective MxMR to be set + * before calling this function. "size" is the number or entries, not a sizeof. + */ +void upmconfig (uint upm, uint * table, uint size) +{ +	int i, mdr, mad, old_mad = 0; +	volatile u32 *mxmr; +	volatile ccsr_lbc_t *lbc = (void *)(CONFIG_SYS_MPC85xx_LBC_ADDR); +	volatile u32 *brp,*orp; +	volatile u8* dummy = NULL; +	int upmmask; + +	switch (upm) { +	case UPMA: +		mxmr = &lbc->mamr; +		upmmask = BR_MS_UPMA; +		break; +	case UPMB: +		mxmr = &lbc->mbmr; +		upmmask = BR_MS_UPMB; +		break; +	case UPMC: +		mxmr = &lbc->mcmr; +		upmmask = BR_MS_UPMC; +		break; +	default: +		printf("%s: Bad UPM index %d to configure\n", __FUNCTION__, upm); +		hang(); +	} + +	/* Find the address for the dummy write transaction */ +	for (brp = &lbc->br0, orp = &lbc->or0, i = 0; i < 8; +		 i++, brp += 2, orp += 2) { + +		/* Look for a valid BR with selected UPM */ +		if ((in_be32(brp) & (BR_V | BR_MSEL)) == (BR_V | upmmask)) { +			dummy = (volatile u8*)(in_be32(brp) & BR_BA); +			break; +		} +	} + +	if (i == 8) { +		printf("Error: %s() could not find matching BR\n", __FUNCTION__); +		hang(); +	} + +	for (i = 0; i < size; i++) { +		/* 1 */ +		out_be32(mxmr,  (in_be32(mxmr) & 0x4fffffc0) | MxMR_OP_WARR | i); +		/* 2 */ +		out_be32(&lbc->mdr, table[i]); +		/* 3 */ +		mdr = in_be32(&lbc->mdr); +		/* 4 */ +		*(volatile u8 *)dummy = 0; +		/* 5 */ +		do { +			mad = in_be32(mxmr) & MxMR_MAD_MSK; +		} while (mad <= old_mad && !(!mad && i == (size-1))); +		old_mad = mad; +	} +	out_be32(mxmr, (in_be32(mxmr) & 0x4fffffc0) | MxMR_OP_NORM); +} + +/* + * Initializes on-chip MMC controllers. + * to override, implement board_mmc_init() + */ +int cpu_mmc_init(bd_t *bis) +{ +#ifdef CONFIG_FSL_ESDHC +	return fsl_esdhc_mmc_init(bis); +#else +	return 0; +#endif +} diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c new file mode 100644 index 000000000..e0126d331 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c @@ -0,0 +1,405 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. + * + * (C) Copyright 2003 Motorola Inc. + * Modified by Xianghua Xiao, X.Xiao@motorola.com + * + * (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 + */ + +#include <common.h> +#include <watchdog.h> +#include <asm/processor.h> +#include <ioports.h> +#include <asm/io.h> +#include <asm/mmu.h> +#include <asm/fsl_law.h> +#include "mp.h" + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_MPC8536 +extern void fsl_serdes_init(void); +#endif + +#ifdef CONFIG_QE +extern qe_iop_conf_t qe_iop_conf_tab[]; +extern void qe_config_iopin(u8 port, u8 pin, int dir, +				int open_drain, int assign); +extern void qe_init(uint qe_base); +extern void qe_reset(void); + +static void config_qe_ioports(void) +{ +	u8      port, pin; +	int     dir, open_drain, assign; +	int     i; + +	for (i = 0; qe_iop_conf_tab[i].assign != QE_IOP_TAB_END; i++) { +		port		= qe_iop_conf_tab[i].port; +		pin		= qe_iop_conf_tab[i].pin; +		dir		= qe_iop_conf_tab[i].dir; +		open_drain	= qe_iop_conf_tab[i].open_drain; +		assign		= qe_iop_conf_tab[i].assign; +		qe_config_iopin(port, pin, dir, open_drain, assign); +	} +} +#endif + +#ifdef CONFIG_CPM2 +void config_8560_ioports (volatile ccsr_cpm_t * cpm) +{ +	int portnum; + +	for (portnum = 0; portnum < 4; portnum++) { +		uint pmsk = 0, +		     ppar = 0, +		     psor = 0, +		     pdir = 0, +		     podr = 0, +		     pdat = 0; +		iop_conf_t *iopc = (iop_conf_t *) & iop_conf_tab[portnum][0]; +		iop_conf_t *eiopc = iopc + 32; +		uint msk = 1; + +		/* +		 * NOTE: +		 * index 0 refers to pin 31, +		 * index 31 refers to pin 0 +		 */ +		while (iopc < eiopc) { +			if (iopc->conf) { +				pmsk |= msk; +				if (iopc->ppar) +					ppar |= msk; +				if (iopc->psor) +					psor |= msk; +				if (iopc->pdir) +					pdir |= msk; +				if (iopc->podr) +					podr |= msk; +				if (iopc->pdat) +					pdat |= msk; +			} + +			msk <<= 1; +			iopc++; +		} + +		if (pmsk != 0) { +			volatile ioport_t *iop = ioport_addr (cpm, portnum); +			uint tpmsk = ~pmsk; + +			/* +			 * the (somewhat confused) paragraph at the +			 * bottom of page 35-5 warns that there might +			 * be "unknown behaviour" when programming +			 * PSORx and PDIRx, if PPARx = 1, so I +			 * decided this meant I had to disable the +			 * dedicated function first, and enable it +			 * last. +			 */ +			iop->ppar &= tpmsk; +			iop->psor = (iop->psor & tpmsk) | psor; +			iop->podr = (iop->podr & tpmsk) | podr; +			iop->pdat = (iop->pdat & tpmsk) | pdat; +			iop->pdir = (iop->pdir & tpmsk) | pdir; +			iop->ppar |= ppar; +		} +	} +} +#endif + +/* + * Breathe some life into the CPU... + * + * Set up the memory map + * initialize a bunch of registers + */ + +#ifdef CONFIG_FSL_CORENET +static void corenet_tb_init(void) +{ +	volatile ccsr_rcpm_t *rcpm = +		(void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR); +	volatile ccsr_pic_t *pic = +		(void *)(CONFIG_SYS_MPC85xx_PIC_ADDR); +	u32 whoami = in_be32(&pic->whoami); + +	/* Enable the timebase register for this core */ +	out_be32(&rcpm->ctbenrl, (1 << whoami)); +} +#endif + +void cpu_init_f (void) +{ +	volatile ccsr_lbc_t *memctl = (void *)(CONFIG_SYS_MPC85xx_LBC_ADDR); +	extern void m8560_cpm_reset (void); +#ifdef CONFIG_MPC8548 +	ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR); +	uint svr = get_svr(); + +	/* +	 * CPU2 errata workaround: A core hang possible while executing +	 * a msync instruction and a snoopable transaction from an I/O +	 * master tagged to make quick forward progress is present. +	 * Fixed in silicon rev 2.1. +	 */ +	if ((SVR_MAJ(svr) == 1) || ((SVR_MAJ(svr) == 2 && SVR_MIN(svr) == 0x0))) +		out_be32(&ecm->eebpcr, in_be32(&ecm->eebpcr) | (1 << 16)); +#endif + +	disable_tlb(14); +	disable_tlb(15); + +#ifdef CONFIG_CPM2 +	config_8560_ioports((ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR); +#endif + +	/* 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(CONFIG_SYS_OR0_REMAP) +	memctl->or0 = CONFIG_SYS_OR0_REMAP; +#endif +#if defined(CONFIG_SYS_OR1_REMAP) +	memctl->or1 = CONFIG_SYS_OR1_REMAP; +#endif + +	/* now restrict to preliminary range */ +	/* if cs1 is already set via debugger, leave cs0/cs1 alone */ +	if (! memctl->br1 & 1) { +#if defined(CONFIG_SYS_BR0_PRELIM) && defined(CONFIG_SYS_OR0_PRELIM) +		memctl->br0 = CONFIG_SYS_BR0_PRELIM; +		memctl->or0 = CONFIG_SYS_OR0_PRELIM; +#endif + +#if defined(CONFIG_SYS_BR1_PRELIM) && defined(CONFIG_SYS_OR1_PRELIM) +		memctl->or1 = CONFIG_SYS_OR1_PRELIM; +		memctl->br1 = CONFIG_SYS_BR1_PRELIM; +#endif +	} + +#if defined(CONFIG_SYS_BR2_PRELIM) && defined(CONFIG_SYS_OR2_PRELIM) +	memctl->or2 = CONFIG_SYS_OR2_PRELIM; +	memctl->br2 = CONFIG_SYS_BR2_PRELIM; +#endif + +#if defined(CONFIG_SYS_BR3_PRELIM) && defined(CONFIG_SYS_OR3_PRELIM) +	memctl->or3 = CONFIG_SYS_OR3_PRELIM; +	memctl->br3 = CONFIG_SYS_BR3_PRELIM; +#endif + +#if defined(CONFIG_SYS_BR4_PRELIM) && defined(CONFIG_SYS_OR4_PRELIM) +	memctl->or4 = CONFIG_SYS_OR4_PRELIM; +	memctl->br4 = CONFIG_SYS_BR4_PRELIM; +#endif + +#if defined(CONFIG_SYS_BR5_PRELIM) && defined(CONFIG_SYS_OR5_PRELIM) +	memctl->or5 = CONFIG_SYS_OR5_PRELIM; +	memctl->br5 = CONFIG_SYS_BR5_PRELIM; +#endif + +#if defined(CONFIG_SYS_BR6_PRELIM) && defined(CONFIG_SYS_OR6_PRELIM) +	memctl->or6 = CONFIG_SYS_OR6_PRELIM; +	memctl->br6 = CONFIG_SYS_BR6_PRELIM; +#endif + +#if defined(CONFIG_SYS_BR7_PRELIM) && defined(CONFIG_SYS_OR7_PRELIM) +	memctl->or7 = CONFIG_SYS_OR7_PRELIM; +	memctl->br7 = CONFIG_SYS_BR7_PRELIM; +#endif + +#if defined(CONFIG_CPM2) +	m8560_cpm_reset(); +#endif +#ifdef CONFIG_QE +	/* Config QE ioports */ +	config_qe_ioports(); +#endif +#if defined(CONFIG_MPC8536) +	fsl_serdes_init(); +#endif +#if defined(CONFIG_FSL_DMA) +	dma_init(); +#endif +#ifdef CONFIG_FSL_CORENET +	corenet_tb_init(); +#endif +	init_used_tlb_cams(); +} + + +/* + * Initialize L2 as cache. + * + * The newer 8548, etc, parts have twice as much cache, but + * use the same bit-encoding as the older 8555, etc, parts. + * + */ + +int cpu_init_r(void) +{ +	puts ("L2:    "); + +#if defined(CONFIG_L2_CACHE) +	volatile ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR; +	volatile uint cache_ctl; +	uint svr, ver; +	uint l2srbar; +	u32 l2siz_field; + +	svr = get_svr(); +	ver = SVR_SOC_VER(svr); + +	asm("msync;isync"); +	cache_ctl = l2cache->l2ctl; + +#if defined(CONFIG_SYS_RAMBOOT) && defined(CONFIG_SYS_INIT_L2_ADDR) +	if (cache_ctl & MPC85xx_L2CTL_L2E) { +		/* Clear L2 SRAM memory-mapped base address */ +		out_be32(&l2cache->l2srbar0, 0x0); +		out_be32(&l2cache->l2srbar1, 0x0); + +		/* set MBECCDIS=0, SBECCDIS=0 */ +		clrbits_be32(&l2cache->l2errdis, +				(MPC85xx_L2ERRDIS_MBECC | +				 MPC85xx_L2ERRDIS_SBECC)); + +		/* set L2E=0, L2SRAM=0 */ +		clrbits_be32(&l2cache->l2ctl, +				(MPC85xx_L2CTL_L2E | +				 MPC85xx_L2CTL_L2SRAM_ENTIRE)); +	} +#endif + +	l2siz_field = (cache_ctl >> 28) & 0x3; + +	switch (l2siz_field) { +	case 0x0: +		printf(" unknown size (0x%08x)\n", cache_ctl); +		return -1; +		break; +	case 0x1: +		if (ver == SVR_8540 || ver == SVR_8560   || +		    ver == SVR_8541 || ver == SVR_8541_E || +		    ver == SVR_8555 || ver == SVR_8555_E) { +			puts("128 KB "); +			/* set L2E=1, L2I=1, & L2BLKSZ=1 (128 Kbyte) */ +			cache_ctl = 0xc4000000; +		} else { +			puts("256 KB "); +			cache_ctl = 0xc0000000; /* set L2E=1, L2I=1, & L2SRAM=0 */ +		} +		break; +	case 0x2: +		if (ver == SVR_8540 || ver == SVR_8560   || +		    ver == SVR_8541 || ver == SVR_8541_E || +		    ver == SVR_8555 || ver == SVR_8555_E) { +			puts("256 KB "); +			/* set L2E=1, L2I=1, & L2BLKSZ=2 (256 Kbyte) */ +			cache_ctl = 0xc8000000; +		} else { +			puts ("512 KB "); +			/* set L2E=1, L2I=1, & L2SRAM=0 */ +			cache_ctl = 0xc0000000; +		} +		break; +	case 0x3: +		puts("1024 KB "); +		/* set L2E=1, L2I=1, & L2SRAM=0 */ +		cache_ctl = 0xc0000000; +		break; +	} + +	if (l2cache->l2ctl & MPC85xx_L2CTL_L2E) { +		puts("already enabled"); +		l2srbar = l2cache->l2srbar0; +#ifdef CONFIG_SYS_INIT_L2_ADDR +		if (l2cache->l2ctl & MPC85xx_L2CTL_L2SRAM_ENTIRE +				&& l2srbar >= CONFIG_SYS_FLASH_BASE) { +			l2srbar = CONFIG_SYS_INIT_L2_ADDR; +			l2cache->l2srbar0 = l2srbar; +			printf("moving to 0x%08x", CONFIG_SYS_INIT_L2_ADDR); +		} +#endif /* CONFIG_SYS_INIT_L2_ADDR */ +		puts("\n"); +	} else { +		asm("msync;isync"); +		l2cache->l2ctl = cache_ctl; /* invalidate & enable */ +		asm("msync;isync"); +		puts("enabled\n"); +	} +#elif defined(CONFIG_BACKSIDE_L2_CACHE) +	u32 l2cfg0 = mfspr(SPRN_L2CFG0); + +	/* invalidate the L2 cache */ +	mtspr(SPRN_L2CSR0, (L2CSR0_L2FI|L2CSR0_L2LFC)); +	while (mfspr(SPRN_L2CSR0) & (L2CSR0_L2FI|L2CSR0_L2LFC)) +		; + +#ifdef CONFIG_SYS_CACHE_STASHING +	/* set stash id to (coreID) * 2 + 32 + L2 (1) */ +	mtspr(SPRN_L2CSR1, (32 + 1)); +#endif + +	/* enable the cache */ +	mtspr(SPRN_L2CSR0, CONFIG_SYS_INIT_L2CSR0); + +	if (CONFIG_SYS_INIT_L2CSR0 & L2CSR0_L2E) { +		while (!(mfspr(SPRN_L2CSR0) & L2CSR0_L2E)) +			; +		printf("%d KB enabled\n", (l2cfg0 & 0x3fff) * 64); +	} +#else +	puts("disabled\n"); +#endif +#ifdef CONFIG_QE +	uint qe_base = CONFIG_SYS_IMMR + 0x00080000; /* QE immr base */ +	qe_init(qe_base); +	qe_reset(); +#endif + +#if defined(CONFIG_MP) +	setup_mp(); +#endif +	return 0; +} + +extern void setup_ivors(void); + +void arch_preboot_os(void) +{ +	u32 msr; + +	/* +	 * We are changing interrupt offsets and are about to boot the OS so +	 * we need to make sure we disable all async interrupts. EE is already +	 * disabled by the time we get called. +	 */ +	msr = mfmsr(); +	msr &= ~(MSR_ME|MSR_CE|MSR_DE); +	mtmsr(msr); + +	setup_ivors(); +} diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init_early.c b/arch/powerpc/cpu/mpc85xx/cpu_init_early.c new file mode 100644 index 000000000..32aa94b61 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/cpu_init_early.c @@ -0,0 +1,112 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * 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 <asm/mmu.h> +#include <asm/fsl_law.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR_PHYS) +#ifdef CONFIG_FSL_CORENET +static void setup_ccsrbar(void) +{ +	u32 temp; +	volatile u32 *ccsr_virt = (volatile u32 *)(CONFIG_SYS_CCSRBAR + 0x1000); +	volatile ccsr_local_t *ccm; + +	/* +	 * We can't call set_law() because we haven't moved +	 * CCSR yet. +	 */ +	ccm = (void *)ccsr_virt; + +	out_be32(&ccm->law[0].lawbarh, +		(u64)CONFIG_SYS_CCSRBAR_PHYS >> 32); +	out_be32(&ccm->law[0].lawbarl, (u32)CONFIG_SYS_CCSRBAR_PHYS); +	out_be32(&ccm->law[0].lawar, +		LAW_EN | (0x1e << 20) | LAW_SIZE_4K); + +	in_be32((u32 *)(ccsr_virt + 0)); +	in_be32((u32 *)(ccsr_virt + 1)); +	isync(); + +	ccm = (void *)CONFIG_SYS_CCSRBAR; +	/* Now use the temporary LAW to move CCSR */ +	out_be32(&ccm->ccsrbarh, (u64)CONFIG_SYS_CCSRBAR_PHYS >> 32); +	out_be32(&ccm->ccsrbarl, (u32)CONFIG_SYS_CCSRBAR_PHYS); +	out_be32(&ccm->ccsrar, CCSRAR_C); +	temp = in_be32(&ccm->ccsrar); +	disable_law(0); +} +#else +static void setup_ccsrbar(void) +{ +	u32 temp; +	volatile u32 *ccsr_virt = (volatile u32 *)(CONFIG_SYS_CCSRBAR + 0x1000); + +	temp = in_be32(ccsr_virt); +	out_be32(ccsr_virt, CONFIG_SYS_CCSRBAR_PHYS >> 12); +	temp = in_be32((volatile u32 *)CONFIG_SYS_CCSRBAR); +} +#endif +#endif + +/* We run cpu_init_early_f in AS = 1 */ +void cpu_init_early_f(void) +{ +	u32 mas0, mas1, mas2, mas3, mas7; +	int i; + +	/* Pointer is writable since we allocated a register for it */ +	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET); + +	/* +	 * Clear initial global data +	 *   we don't use memset so we can share this code with NAND_SPL +	 */ +	for (i = 0; i < sizeof(gd_t); i++) +		((char *)gd)[i] = 0; + +	mas0 = MAS0_TLBSEL(0) | MAS0_ESEL(0); +	mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | MAS1_TSIZE(BOOKE_PAGESZ_4K); +	mas2 = FSL_BOOKE_MAS2(CONFIG_SYS_CCSRBAR, MAS2_I|MAS2_G); +	mas3 = FSL_BOOKE_MAS3(CONFIG_SYS_CCSRBAR_PHYS, 0, MAS3_SW|MAS3_SR); +	mas7 = FSL_BOOKE_MAS7(CONFIG_SYS_CCSRBAR_PHYS); + +	write_tlb(mas0, mas1, mas2, mas3, mas7); + +	/* set up CCSR if we want it moved */ +#if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR_PHYS) +	mas0 = MAS0_TLBSEL(0) | MAS0_ESEL(1); +	/* mas1 is the same as above */ +	mas2 = FSL_BOOKE_MAS2(CONFIG_SYS_CCSRBAR + 0x1000, MAS2_I|MAS2_G); +	mas3 = FSL_BOOKE_MAS3(CONFIG_SYS_CCSRBAR_DEFAULT, 0, MAS3_SW|MAS3_SR); +	mas7 = FSL_BOOKE_MAS7(CONFIG_SYS_CCSRBAR_DEFAULT); + +	write_tlb(mas0, mas1, mas2, mas3, mas7); + +	setup_ccsrbar(); +#endif + +	init_laws(); +	invalidate_tlb(0); +	init_tlbs(); +} diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init_nand.c b/arch/powerpc/cpu/mpc85xx/cpu_init_nand.c new file mode 100644 index 000000000..184cca4c5 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/cpu_init_nand.c @@ -0,0 +1,63 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> + +void cpu_init_f(void) +{ +	ccsr_lbc_t *lbc = (void *)(CONFIG_SYS_MPC85xx_LBC_ADDR); + +	/* +	 * LCRR - Clock Ratio Register - set up local bus timing +	 * when needed +	 */ +	out_be32(&lbc->lcrr, LCRR_DBYP | LCRR_CLKDIV_8); + +#if defined(CONFIG_NAND_BR_PRELIM) && defined(CONFIG_NAND_OR_PRELIM) +	out_be32(&lbc->br0, CONFIG_NAND_BR_PRELIM); +	out_be32(&lbc->or0, CONFIG_NAND_OR_PRELIM); +#else +#error  CONFIG_NAND_BR_PRELIM, CONFIG_NAND_OR_PRELIM must be defined +#endif + +#if defined(CONFIG_SYS_RAMBOOT) && defined(CONFIG_SYS_INIT_L2_ADDR) +	ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR; +	char *l2srbar; +	int i; + +	out_be32(&l2cache->l2srbar0, CONFIG_SYS_INIT_L2_ADDR); + +	/* set MBECCDIS=1, SBECCDIS=1 */ +	out_be32(&l2cache->l2errdis, +		(MPC85xx_L2ERRDIS_MBECC | MPC85xx_L2ERRDIS_SBECC)); + +	/* set L2E=1 & L2SRAM=001 */ +	out_be32(&l2cache->l2ctl, +		(MPC85xx_L2CTL_L2E | MPC85xx_L2CTL_L2SRAM_ENTIRE)); + +	/* Initialize L2 SRAM to zero */ +	l2srbar = (char *)CONFIG_SYS_INIT_L2_ADDR; +	for (i = 0; i < CONFIG_SYS_L2_SIZE; i++) +		l2srbar[i] = 0; +#endif +} diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen1.c b/arch/powerpc/cpu/mpc85xx/ddr-gen1.c new file mode 100644 index 000000000..54437dd0c --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/ddr-gen1.c @@ -0,0 +1,89 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/fsl_ddr_sdram.h> + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, +			     unsigned int ctrl_num) +{ +	unsigned int i; +	volatile ccsr_ddr_t *ddr = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR; + +	if (ctrl_num != 0) { +		printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); +		return; +	} + +	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { +		if (i == 0) { +			out_be32(&ddr->cs0_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs0_config, regs->cs[i].config); + +		} else if (i == 1) { +			out_be32(&ddr->cs1_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs1_config, regs->cs[i].config); + +		} else if (i == 2) { +			out_be32(&ddr->cs2_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs2_config, regs->cs[i].config); + +		} else if (i == 3) { +			out_be32(&ddr->cs3_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs3_config, regs->cs[i].config); +		} +	} + +	out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1); +	out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2); +	out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode); +	out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); +#if defined(CONFIG_MPC8555) || defined(CONFIG_MPC8541) +	out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl); +#endif + +	/* +	 * 200 painful micro-seconds must elapse between +	 * the DDR clock setup and the DDR config enable. +	 */ +	udelay(200); +	asm volatile("sync;isync"); + +	out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg); + +	asm("sync;isync;msync"); +	udelay(500); +} + +#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) +{ +	volatile ccsr_ddr_t *ddr= (void *)(CONFIG_SYS_MPC85xx_DDR_ADDR); + +	dma_meminit(CONFIG_MEM_INIT_VALUE, dram_size); + +	/* +	 * Enable errors for ECC. +	 */ +	debug("DMA DDR: err_disable = 0x%08x\n", ddr->err_disable); +	ddr->err_disable = 0x00000000; +	asm("sync;isync;msync"); +	debug("DMA DDR: err_disable = 0x%08x\n", ddr->err_disable); +} + +#endif	/* CONFIG_DDR_ECC  && ! CONFIG_ECC_INIT_VIA_DDRCONTROLLER */ diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen2.c b/arch/powerpc/cpu/mpc85xx/ddr-gen2.c new file mode 100644 index 000000000..655f99c02 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/ddr-gen2.c @@ -0,0 +1,74 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/fsl_ddr_sdram.h> + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, +			     unsigned int ctrl_num) +{ +	unsigned int i; +	volatile ccsr_ddr_t *ddr = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR; + +	if (ctrl_num) { +		printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); +		return; +	} + +	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { +		if (i == 0) { +			out_be32(&ddr->cs0_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs0_config, regs->cs[i].config); + +		} else if (i == 1) { +			out_be32(&ddr->cs1_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs1_config, regs->cs[i].config); + +		} else if (i == 2) { +			out_be32(&ddr->cs2_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs2_config, regs->cs[i].config); + +		} else if (i == 3) { +			out_be32(&ddr->cs3_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs3_config, regs->cs[i].config); +		} +	} + +	out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3); +	out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0); +	out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1); +	out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2); +	out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); +	out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode); +	out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2); +	out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl); +	out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); +	out_be32(&ddr->sdram_data_init, regs->ddr_data_init); +	out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl); +	out_be32(&ddr->init_addr, regs->ddr_init_addr); +	out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr); + +	/* +	 * 200 painful micro-seconds must elapse between +	 * the DDR clock setup and the DDR config enable. +	 */ +	udelay(200); +	asm volatile("sync;isync"); + +	out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg); + +	/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done.  */ +	while (in_be32(&ddr->sdram_cfg_2) & 0x10) { +		udelay(10000);		/* throttle polling rate */ +	} +} diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c new file mode 100644 index 000000000..0691ca455 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c @@ -0,0 +1,116 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/fsl_ddr_sdram.h> + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, +			     unsigned int ctrl_num) +{ +	unsigned int i; +	volatile ccsr_ddr_t *ddr; +	u32 temp_sdram_cfg; + +	switch (ctrl_num) { +	case 0: +		ddr = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR; +		break; +	case 1: +		ddr = (void *)CONFIG_SYS_MPC85xx_DDR2_ADDR; +		break; +	default: +		printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); +		return; +	} + +	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { +		if (i == 0) { +			out_be32(&ddr->cs0_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs0_config, regs->cs[i].config); +			out_be32(&ddr->cs0_config_2, regs->cs[i].config_2); + +		} else if (i == 1) { +			out_be32(&ddr->cs1_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs1_config, regs->cs[i].config); +			out_be32(&ddr->cs1_config_2, regs->cs[i].config_2); + +		} else if (i == 2) { +			out_be32(&ddr->cs2_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs2_config, regs->cs[i].config); +			out_be32(&ddr->cs2_config_2, regs->cs[i].config_2); + +		} else if (i == 3) { +			out_be32(&ddr->cs3_bnds, regs->cs[i].bnds); +			out_be32(&ddr->cs3_config, regs->cs[i].config); +			out_be32(&ddr->cs3_config_2, regs->cs[i].config_2); +		} +	} + +	out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3); +	out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0); +	out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1); +	out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2); +	out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); +	out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode); +	out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2); +	out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl); +	out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); +	out_be32(&ddr->sdram_data_init, regs->ddr_data_init); +	out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl); +	out_be32(&ddr->init_addr, regs->ddr_init_addr); +	out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr); + +	out_be32(&ddr->timing_cfg_4, regs->timing_cfg_4); +	out_be32(&ddr->timing_cfg_5, regs->timing_cfg_5); +	out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl); +	out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl); +	out_be32(&ddr->ddr_sr_cntr, regs->ddr_sr_cntr); +	out_be32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1); +	out_be32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2); + +	/* Set, but do not enable the memory */ +	temp_sdram_cfg = regs->ddr_sdram_cfg; +	temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN); +	out_be32(&ddr->sdram_cfg, temp_sdram_cfg); +	/* +	 * For 8572 DDR1 erratum - DDR controller may enter illegal state +	 * when operatiing in 32-bit bus mode with 4-beat bursts, +	 * This erratum does not affect DDR3 mode, only for DDR2 mode. +	 */ +#ifdef CONFIG_MPC8572 +	if ((((in_be32(&ddr->sdram_cfg) >> 24) & 0x7) == SDRAM_TYPE_DDR2) +	    && in_be32(&ddr->sdram_cfg) & 0x80000) { +		/* set DEBUG_1[31] */ +		u32 temp = in_be32(&ddr->debug_1); +		out_be32(&ddr->debug_1, temp | 1); +	} +#endif + +	/* +	 * 500 painful micro-seconds must elapse between +	 * the DDR clock setup and the DDR config enable. +	 * DDR2 need 200 us, and DDR3 need 500 us from spec, +	 * we choose the max, that is 500 us for all of case. +	 */ +	udelay(500); +	asm volatile("sync;isync"); + +	/* Let the controller go */ +	temp_sdram_cfg = in_be32(&ddr->sdram_cfg); +	out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN); + +	/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done.  */ +	while (in_be32(&ddr->sdram_cfg_2) & 0x10) { +		udelay(10000);		/* throttle polling rate */ +	} +} diff --git a/arch/powerpc/cpu/mpc85xx/ether_fcc.c b/arch/powerpc/cpu/mpc85xx/ether_fcc.c new file mode 100644 index 000000000..5f1414d75 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/ether_fcc.c @@ -0,0 +1,469 @@ +/* + * MPC8560 FCC Fast Ethernet + * Copyright (c) 2003 Motorola,Inc. + * Xianghua Xiao, (X.Xiao@motorola.com) + * + * Copyright (c) 2000 MontaVista Software, Inc.   Dan Malek (dmalek@jlc.net) + * + * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.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 + */ + +/* + * MPC8560 FCC Fast Ethernet + * Basic ET HW initialization and packet RX/TX routines + * + * This code will not perform the IO port configuration. This should be + * done in the iop_conf_t structure specific for the board. + * + * TODO: + * add a PHY driver to do the negotiation + * reflect negotiation results in FPSMR + * look for ways to configure the board specific stuff elsewhere, eg. + *    config_xxx.h or the board directory + */ + +#include <common.h> +#include <malloc.h> +#include <asm/cpm_85xx.h> +#include <command.h> +#include <config.h> +#include <net.h> + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +#include <miiphy.h> +#endif + +#if defined(CONFIG_ETHER_ON_FCC) && defined(CONFIG_CMD_NET) && \ +	defined(CONFIG_NET_MULTI) + +static struct ether_fcc_info_s +{ +	int ether_index; +	int proff_enet; +	ulong cpm_cr_enet_sblock; +	ulong cpm_cr_enet_page; +	ulong cmxfcr_mask; +	ulong cmxfcr_value; +} +	ether_fcc_info[] = +{ +#ifdef CONFIG_ETHER_ON_FCC1 +{ +	0, +	PROFF_FCC1, +	CPM_CR_FCC1_SBLOCK, +	CPM_CR_FCC1_PAGE, +	CONFIG_SYS_CMXFCR_MASK1, +	CONFIG_SYS_CMXFCR_VALUE1 +}, +#endif + +#ifdef CONFIG_ETHER_ON_FCC2 +{ +	1, +	PROFF_FCC2, +	CPM_CR_FCC2_SBLOCK, +	CPM_CR_FCC2_PAGE, +	CONFIG_SYS_CMXFCR_MASK2, +	CONFIG_SYS_CMXFCR_VALUE2 +}, +#endif + +#ifdef CONFIG_ETHER_ON_FCC3 +{ +	2, +	PROFF_FCC3, +	CPM_CR_FCC3_SBLOCK, +	CPM_CR_FCC3_PAGE, +	CONFIG_SYS_CMXFCR_MASK3, +	CONFIG_SYS_CMXFCR_VALUE3 +}, +#endif +}; + +/*---------------------------------------------------------------------*/ + +/* Maximum input DMA size.  Must be a should(?) be a multiple of 4. */ +#define PKT_MAXDMA_SIZE         1520 + +/* The FCC stores dest/src/type, data, and checksum for receive packets. */ +#define PKT_MAXBUF_SIZE         1518 +#define PKT_MINBUF_SIZE         64 + +/* Maximum input buffer size.  Must be a multiple of 32. */ +#define PKT_MAXBLR_SIZE         1536 + +#define TOUT_LOOP 1000000 + +#define TX_BUF_CNT 2 + +static uint rxIdx;	/* index of the current RX buffer */ +static uint txIdx;	/* index of the current TX buffer */ + +/* + * FCC Ethernet Tx and Rx buffer descriptors. + * Provide for Double Buffering + * Note: PKTBUFSRX is defined in net.h + */ + +typedef volatile struct rtxbd { +    cbd_t rxbd[PKTBUFSRX]; +    cbd_t txbd[TX_BUF_CNT]; +} RTXBD; + +/*  Good news: the FCC supports external BDs! */ +#ifdef __GNUC__ +static RTXBD rtx __attribute__ ((aligned(8))); +#else +#error "rtx must be 64-bit aligned" +#endif + +#undef ET_DEBUG + +static int fec_send(struct eth_device* dev, volatile void *packet, int length) +{ +    int i = 0; +    int result = 0; + +    if (length <= 0) { +	printf("fec: bad packet size: %d\n", length); +	goto out; +    } + +    for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) { +	if (i >= TOUT_LOOP) { +	    printf("fec: tx buffer not ready\n"); +	    goto out; +	} +    } + +    rtx.txbd[txIdx].cbd_bufaddr = (uint)packet; +    rtx.txbd[txIdx].cbd_datlen = length; +    rtx.txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST | \ +			       BD_ENET_TX_TC | BD_ENET_TX_PAD); + +    for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) { +	if (i >= TOUT_LOOP) { +	    printf("fec: tx error\n"); +	    goto out; +	} +    } + +#ifdef ET_DEBUG +    printf("cycles: 0x%x txIdx=0x%04x status: 0x%04x\n", i, txIdx,rtx.txbd[txIdx].cbd_sc); +    printf("packets at 0x%08x, length_in_bytes=0x%x\n",(uint)packet,length); +    for(i=0;i<(length/16 + 1);i++) { +	 printf("%08x %08x %08x %08x\n",*((uint *)rtx.txbd[txIdx].cbd_bufaddr+i*4),\ +    *((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 1),*((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 2), \ +    *((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 3)); +    } +#endif + +    /* return only status bits */ +    result = rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_STATS; +    txIdx = (txIdx + 1) % TX_BUF_CNT; + +out: +    return result; +} + +static int fec_recv(struct eth_device* dev) +{ +    int length; + +    for (;;) +    { +	if (rtx.rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) { +	    length = -1; +	    break;     /* nothing received - leave for() loop */ +	} +	length = rtx.rxbd[rxIdx].cbd_datlen; + +	if (rtx.rxbd[rxIdx].cbd_sc & 0x003f) { +	    printf("fec: rx error %04x\n", rtx.rxbd[rxIdx].cbd_sc); +	} +	else { +	    /* Pass the packet up to the protocol layers. */ +	    NetReceive(NetRxPackets[rxIdx], length - 4); +	} + + +	/* Give the buffer back to the FCC. */ +	rtx.rxbd[rxIdx].cbd_datlen = 0; + +	/* wrap around buffer index when necessary */ +	if ((rxIdx + 1) >= PKTBUFSRX) { +	    rtx.rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); +	    rxIdx = 0; +	} +	else { +	    rtx.rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY; +	    rxIdx++; +	} +    } +    return length; +} + + +static int fec_init(struct eth_device* dev, bd_t *bis) +{ +    struct ether_fcc_info_s * info = dev->priv; +    int i; +    volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; +    volatile ccsr_cpm_cp_t *cp = &(cpm->im_cpm_cp); +    fcc_enet_t *pram_ptr; +    unsigned long mem_addr; + +#if 0 +    mii_discover_phy(); +#endif + +    /* 28.9 - (1-2): ioports have been set up already */ + +    /* 28.9 - (3): connect FCC's tx and rx clocks */ +    cpm->im_cpm_mux.cmxuar = 0; /* ATM */ +    cpm->im_cpm_mux.cmxfcr = (cpm->im_cpm_mux.cmxfcr & ~info->cmxfcr_mask) | +							info->cmxfcr_value; + +    /* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, set Mode Ethernet */ +    if(info->ether_index == 0) { +	cpm->im_cpm_fcc1.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32; +    } else if (info->ether_index == 1) { +	cpm->im_cpm_fcc2.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32; +    } else if (info->ether_index == 2) { +	cpm->im_cpm_fcc3.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32; +    } + +    /* 28.9 - (5): FPSMR: enable full duplex, select CCITT CRC for Ethernet,MII */ +    if(info->ether_index == 0) { +	cpm->im_cpm_fcc1.fpsmr = CONFIG_SYS_FCC_PSMR | FCC_PSMR_ENCRC; +    } else if (info->ether_index == 1){ +	cpm->im_cpm_fcc2.fpsmr = CONFIG_SYS_FCC_PSMR | FCC_PSMR_ENCRC; +    } else if (info->ether_index == 2){ +	cpm->im_cpm_fcc3.fpsmr = CONFIG_SYS_FCC_PSMR | FCC_PSMR_ENCRC; +    } + +    /* 28.9 - (6): FDSR: Ethernet Syn */ +    if(info->ether_index == 0) { +	cpm->im_cpm_fcc1.fdsr = 0xD555; +    } else if (info->ether_index == 1) { +	cpm->im_cpm_fcc2.fdsr = 0xD555; +    } else if (info->ether_index == 2) { +	cpm->im_cpm_fcc3.fdsr = 0xD555; +    } + +    /* reset indeces to current rx/tx bd (see eth_send()/eth_rx()) */ +    rxIdx = 0; +    txIdx = 0; + +    /* Setup Receiver Buffer Descriptors */ +    for (i = 0; i < PKTBUFSRX; i++) +    { +      rtx.rxbd[i].cbd_sc = BD_ENET_RX_EMPTY; +      rtx.rxbd[i].cbd_datlen = 0; +      rtx.rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i]; +    } +    rtx.rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP; + +    /* Setup Ethernet Transmitter Buffer Descriptors */ +    for (i = 0; i < TX_BUF_CNT; i++) +    { +      rtx.txbd[i].cbd_sc = 0; +      rtx.txbd[i].cbd_datlen = 0; +      rtx.txbd[i].cbd_bufaddr = 0; +    } +    rtx.txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP; + +    /* 28.9 - (7): initialize parameter ram */ +    pram_ptr = (fcc_enet_t *)&(cpm->im_dprambase[info->proff_enet]); + +    /* clear whole structure to make sure all reserved fields are zero */ +    memset((void*)pram_ptr, 0, sizeof(fcc_enet_t)); + +    /* +     * common Parameter RAM area +     * +     * Allocate space in the reserved FCC area of DPRAM for the +     * internal buffers.  No one uses this space (yet), so we +     * can do this.  Later, we will add resource management for +     * this area. +     * CPM_FCC_SPECIAL_BASE:	0xB000 for MPC8540, MPC8560 +     *				0x9000 for MPC8541, MPC8555 +     */ +    mem_addr = CPM_FCC_SPECIAL_BASE + ((info->ether_index) * 64); +    pram_ptr->fen_genfcc.fcc_riptr = mem_addr; +    pram_ptr->fen_genfcc.fcc_tiptr = mem_addr+32; +    /* +     * Set maximum bytes per receive buffer. +     * It must be a multiple of 32. +     */ +    pram_ptr->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE; /* 1536 */ +    /* localbus SDRAM should be preferred */ +    pram_ptr->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB | +				       CONFIG_SYS_CPMFCR_RAMTYPE) << 24; +    pram_ptr->fen_genfcc.fcc_rbase = (unsigned int)(&rtx.rxbd[rxIdx]); +    pram_ptr->fen_genfcc.fcc_rbdstat = 0; +    pram_ptr->fen_genfcc.fcc_rbdlen = 0; +    pram_ptr->fen_genfcc.fcc_rdptr = 0; +    /* localbus SDRAM should be preferred */ +    pram_ptr->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB | +				       CONFIG_SYS_CPMFCR_RAMTYPE) << 24; +    pram_ptr->fen_genfcc.fcc_tbase = (unsigned int)(&rtx.txbd[txIdx]); +    pram_ptr->fen_genfcc.fcc_tbdstat = 0; +    pram_ptr->fen_genfcc.fcc_tbdlen = 0; +    pram_ptr->fen_genfcc.fcc_tdptr = 0; + +    /* protocol-specific area */ +    pram_ptr->fen_statbuf = 0x0; +    pram_ptr->fen_cmask = 0xdebb20e3;	/* CRC mask */ +    pram_ptr->fen_cpres = 0xffffffff;	/* CRC preset */ +    pram_ptr->fen_crcec = 0; +    pram_ptr->fen_alec = 0; +    pram_ptr->fen_disfc = 0; +    pram_ptr->fen_retlim = 15;		/* Retry limit threshold */ +    pram_ptr->fen_retcnt = 0; +    pram_ptr->fen_pper = 0; +    pram_ptr->fen_boffcnt = 0; +    pram_ptr->fen_gaddrh = 0; +    pram_ptr->fen_gaddrl = 0; +    pram_ptr->fen_mflr = PKT_MAXBUF_SIZE;   /* maximum frame length register */ +    /* +     * Set Ethernet station address. +     * +     * This is supplied in the board information structure, so we +     * copy that into the controller. +     * So far we have only been given one Ethernet address. We make +     * it unique by setting a few bits in the upper byte of the +     * non-static part of the address. +     */ +#define ea eth_get_dev()->enetaddr +    pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; +    pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; +    pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; +#undef ea +    pram_ptr->fen_ibdcount = 0; +    pram_ptr->fen_ibdstart = 0; +    pram_ptr->fen_ibdend = 0; +    pram_ptr->fen_txlen = 0; +    pram_ptr->fen_iaddrh = 0;  /* disable hash */ +    pram_ptr->fen_iaddrl = 0; +    pram_ptr->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register: 64 */ +    /* pad pointer. use tiptr since we don't need a specific padding char */ +    pram_ptr->fen_padptr = pram_ptr->fen_genfcc.fcc_tiptr; +    pram_ptr->fen_maxd1 = PKT_MAXDMA_SIZE;	/* maximum DMA1 length:1520 */ +    pram_ptr->fen_maxd2 = PKT_MAXDMA_SIZE;	/* maximum DMA2 length:1520 */ + +#if defined(ET_DEBUG) +    printf("parm_ptr(0xff788500) = %p\n",pram_ptr); +    printf("pram_ptr->fen_genfcc.fcc_rbase %08x\n", +	pram_ptr->fen_genfcc.fcc_rbase); +    printf("pram_ptr->fen_genfcc.fcc_tbase %08x\n", +	pram_ptr->fen_genfcc.fcc_tbase); +#endif + +    /* 28.9 - (8)(9): clear out events in FCCE */ +    /* 28.9 - (9): FCCM: mask all events */ +    if(info->ether_index == 0) { +	cpm->im_cpm_fcc1.fcce = ~0x0; +	cpm->im_cpm_fcc1.fccm = 0; +    } else if (info->ether_index == 1) { +	cpm->im_cpm_fcc2.fcce = ~0x0; +	cpm->im_cpm_fcc2.fccm = 0; +    } else if (info->ether_index == 2) { +	cpm->im_cpm_fcc3.fcce = ~0x0; +	cpm->im_cpm_fcc3.fccm = 0; +    } + +    /* 28.9 - (10-12): we don't use ethernet interrupts */ + +    /* 28.9 - (13) +     * +     * Let's re-initialize the channel now.  We have to do it later +     * than the manual describes because we have just now finished +     * the BD initialization. +     */ +    cp->cpcr = mk_cr_cmd(info->cpm_cr_enet_page, +			    info->cpm_cr_enet_sblock, +			    0x0c, +			    CPM_CR_INIT_TRX) | CPM_CR_FLG; +    do { +	__asm__ __volatile__ ("eieio"); +    } while (cp->cpcr & CPM_CR_FLG); + +    /* 28.9 - (14): enable tx/rx in gfmr */ +    if(info->ether_index == 0) { +	cpm->im_cpm_fcc1.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR; +    } else if (info->ether_index == 1) { +	cpm->im_cpm_fcc2.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR; +    } else if (info->ether_index == 2) { +	cpm->im_cpm_fcc3.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR; +    } + +    return 1; +} + +static void fec_halt(struct eth_device* dev) +{ +    struct ether_fcc_info_s * info = dev->priv; +    volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; + +    /* write GFMR: disable tx/rx */ +    if(info->ether_index == 0) { +	cpm->im_cpm_fcc1.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR); +    } else if(info->ether_index == 1) { +	cpm->im_cpm_fcc2.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR); +    } else if(info->ether_index == 2) { +	cpm->im_cpm_fcc3.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR); +    } +} + +int fec_initialize(bd_t *bis) +{ +	struct eth_device* dev; +	int i; + +	for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++) +	{ +		dev = (struct eth_device*) malloc(sizeof *dev); +		memset(dev, 0, sizeof *dev); + +		sprintf(dev->name, "FCC%d ETHERNET", +			ether_fcc_info[i].ether_index + 1); +		dev->priv   = ðer_fcc_info[i]; +		dev->init   = fec_init; +		dev->halt   = fec_halt; +		dev->send   = fec_send; +		dev->recv   = fec_recv; + +		eth_register(dev); + +#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) \ +		&& defined(CONFIG_BITBANGMII) +		miiphy_register(dev->name, +				bb_miiphy_read,	bb_miiphy_write); +#endif +	} + +	return 1; +} + +#endif diff --git a/arch/powerpc/cpu/mpc85xx/fdt.c b/arch/powerpc/cpu/mpc85xx/fdt.c new file mode 100644 index 000000000..1d11ab470 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/fdt.c @@ -0,0 +1,417 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. + * + * (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 + */ + +#include <common.h> +#include <libfdt.h> +#include <fdt_support.h> +#include <asm/processor.h> +#include <linux/ctype.h> +#ifdef CONFIG_FSL_ESDHC +#include <fsl_esdhc.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +extern void ft_qe_setup(void *blob); +extern void ft_fixup_num_cores(void *blob); + +#ifdef CONFIG_MP +#include "mp.h" + +void ft_fixup_cpu(void *blob, u64 memory_limit) +{ +	int off; +	ulong spin_tbl_addr = get_spin_phys_addr(); +	u32 bootpg = determine_mp_bootpg(); +	u32 id = get_my_id(); + +	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); +	while (off != -FDT_ERR_NOTFOUND) { +		u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0); + +		if (reg) { +			if (*reg == id) { +				fdt_setprop_string(blob, off, "status", "okay"); +			} else { +				u64 val = *reg * SIZE_BOOT_ENTRY + spin_tbl_addr; +				val = cpu_to_fdt32(val); +				fdt_setprop_string(blob, off, "status", +								"disabled"); +				fdt_setprop_string(blob, off, "enable-method", +								"spin-table"); +				fdt_setprop(blob, off, "cpu-release-addr", +						&val, sizeof(val)); +			} +		} else { +			printf ("cpu NULL\n"); +		} +		off = fdt_node_offset_by_prop_value(blob, off, +				"device_type", "cpu", 4); +	} + +	/* Reserve the boot page so OSes dont use it */ +	if ((u64)bootpg < memory_limit) { +		off = fdt_add_mem_rsv(blob, bootpg, (u64)4096); +		if (off < 0) +			printf("%s: %s\n", __FUNCTION__, fdt_strerror(off)); +	} +} +#endif + +#define ft_fixup_l3cache(x, y) + +#if defined(CONFIG_L2_CACHE) +/* return size in kilobytes */ +static inline u32 l2cache_size(void) +{ +	volatile ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR; +	volatile u32 l2siz_field = (l2cache->l2ctl >> 28) & 0x3; +	u32 ver = SVR_SOC_VER(get_svr()); + +	switch (l2siz_field) { +	case 0x0: +		break; +	case 0x1: +		if (ver == SVR_8540 || ver == SVR_8560   || +		    ver == SVR_8541 || ver == SVR_8541_E || +		    ver == SVR_8555 || ver == SVR_8555_E) +			return 128; +		else +			return 256; +		break; +	case 0x2: +		if (ver == SVR_8540 || ver == SVR_8560   || +		    ver == SVR_8541 || ver == SVR_8541_E || +		    ver == SVR_8555 || ver == SVR_8555_E) +			return 256; +		else +			return 512; +		break; +	case 0x3: +		return 1024; +		break; +	} + +	return 0; +} + +static inline void ft_fixup_l2cache(void *blob) +{ +	int len, off; +	u32 *ph; +	struct cpu_type *cpu = identify_cpu(SVR_SOC_VER(get_svr())); +	char compat_buf[38]; + +	const u32 line_size = 32; +	const u32 num_ways = 8; +	const u32 size = l2cache_size() * 1024; +	const u32 num_sets = size / (line_size * num_ways); + +	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); +	if (off < 0) { +		debug("no cpu node fount\n"); +		return; +	} + +	ph = (u32 *)fdt_getprop(blob, off, "next-level-cache", 0); + +	if (ph == NULL) { +		debug("no next-level-cache property\n"); +		return ; +	} + +	off = fdt_node_offset_by_phandle(blob, *ph); +	if (off < 0) { +		printf("%s: %s\n", __func__, fdt_strerror(off)); +		return ; +	} + +	if (cpu) { +		if (isdigit(cpu->name[0])) +			len = sprintf(compat_buf, +				"fsl,mpc%s-l2-cache-controller", cpu->name); +		else +			len = sprintf(compat_buf, +				"fsl,%c%s-l2-cache-controller", +				tolower(cpu->name[0]), cpu->name + 1); + +		sprintf(&compat_buf[len + 1], "cache"); +	} +	fdt_setprop(blob, off, "cache-unified", NULL, 0); +	fdt_setprop_cell(blob, off, "cache-block-size", line_size); +	fdt_setprop_cell(blob, off, "cache-size", size); +	fdt_setprop_cell(blob, off, "cache-sets", num_sets); +	fdt_setprop_cell(blob, off, "cache-level", 2); +	fdt_setprop(blob, off, "compatible", compat_buf, sizeof(compat_buf)); + +	/* we dont bother w/L3 since no platform of this type has one */ +} +#elif defined(CONFIG_BACKSIDE_L2_CACHE) +static inline void ft_fixup_l2cache(void *blob) +{ +	int off, l2_off, l3_off = -1; +	u32 *ph; +	u32 l2cfg0 = mfspr(SPRN_L2CFG0); +	u32 size, line_size, num_ways, num_sets; + +	size = (l2cfg0 & 0x3fff) * 64 * 1024; +	num_ways = ((l2cfg0 >> 14) & 0x1f) + 1; +	line_size = (((l2cfg0 >> 23) & 0x3) + 1) * 32; +	num_sets = size / (line_size * num_ways); + +	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); + +	while (off != -FDT_ERR_NOTFOUND) { +		ph = (u32 *)fdt_getprop(blob, off, "next-level-cache", 0); + +		if (ph == NULL) { +			debug("no next-level-cache property\n"); +			goto next; +		} + +		l2_off = fdt_node_offset_by_phandle(blob, *ph); +		if (l2_off < 0) { +			printf("%s: %s\n", __func__, fdt_strerror(off)); +			goto next; +		} + +#ifdef CONFIG_SYS_CACHE_STASHING +		{ +			u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0); +			if (reg) +				fdt_setprop_cell(blob, l2_off, "cache-stash-id", +					 (*reg * 2) + 32 + 1); +		} +#endif + +		fdt_setprop(blob, l2_off, "cache-unified", NULL, 0); +		fdt_setprop_cell(blob, l2_off, "cache-block-size", line_size); +		fdt_setprop_cell(blob, l2_off, "cache-size", size); +		fdt_setprop_cell(blob, l2_off, "cache-sets", num_sets); +		fdt_setprop_cell(blob, l2_off, "cache-level", 2); +		fdt_setprop(blob, l2_off, "compatible", "cache", 6); + +		if (l3_off < 0) { +			ph = (u32 *)fdt_getprop(blob, l2_off, "next-level-cache", 0); + +			if (ph == NULL) { +				debug("no next-level-cache property\n"); +				goto next; +			} +			l3_off = *ph; +		} +next: +		off = fdt_node_offset_by_prop_value(blob, off, +				"device_type", "cpu", 4); +	} +	if (l3_off > 0) { +		l3_off = fdt_node_offset_by_phandle(blob, l3_off); +		if (l3_off < 0) { +			printf("%s: %s\n", __func__, fdt_strerror(off)); +			return ; +		} +		ft_fixup_l3cache(blob, l3_off); +	} +} +#else +#define ft_fixup_l2cache(x) +#endif + +static inline void ft_fixup_cache(void *blob) +{ +	int off; + +	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); + +	while (off != -FDT_ERR_NOTFOUND) { +		u32 l1cfg0 = mfspr(SPRN_L1CFG0); +		u32 l1cfg1 = mfspr(SPRN_L1CFG1); +		u32 isize, iline_size, inum_sets, inum_ways; +		u32 dsize, dline_size, dnum_sets, dnum_ways; + +		/* d-side config */ +		dsize = (l1cfg0 & 0x7ff) * 1024; +		dnum_ways = ((l1cfg0 >> 11) & 0xff) + 1; +		dline_size = (((l1cfg0 >> 23) & 0x3) + 1) * 32; +		dnum_sets = dsize / (dline_size * dnum_ways); + +		fdt_setprop_cell(blob, off, "d-cache-block-size", dline_size); +		fdt_setprop_cell(blob, off, "d-cache-size", dsize); +		fdt_setprop_cell(blob, off, "d-cache-sets", dnum_sets); + +#ifdef CONFIG_SYS_CACHE_STASHING +		{ +			u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0); +			if (reg) +				fdt_setprop_cell(blob, off, "cache-stash-id", +					 (*reg * 2) + 32 + 0); +		} +#endif + +		/* i-side config */ +		isize = (l1cfg1 & 0x7ff) * 1024; +		inum_ways = ((l1cfg1 >> 11) & 0xff) + 1; +		iline_size = (((l1cfg1 >> 23) & 0x3) + 1) * 32; +		inum_sets = isize / (iline_size * inum_ways); + +		fdt_setprop_cell(blob, off, "i-cache-block-size", iline_size); +		fdt_setprop_cell(blob, off, "i-cache-size", isize); +		fdt_setprop_cell(blob, off, "i-cache-sets", inum_sets); + +		off = fdt_node_offset_by_prop_value(blob, off, +				"device_type", "cpu", 4); +	} + +	ft_fixup_l2cache(blob); +} + + +void fdt_add_enet_stashing(void *fdt) +{ +	do_fixup_by_compat(fdt, "gianfar", "bd-stash", NULL, 0, 1); + +	do_fixup_by_compat_u32(fdt, "gianfar", "rx-stash-len", 96, 1); + +	do_fixup_by_compat_u32(fdt, "gianfar", "rx-stash-idx", 0, 1); +} + +#if defined(CONFIG_SYS_DPAA_FMAN) || defined(CONFIG_SYS_DPAA_PME) +static void ft_fixup_clks(void *blob, const char *alias, unsigned long freq) +{ +	const char *path = fdt_get_alias(blob, alias); + +	int off = fdt_path_offset(blob, path); + +	if (off >= 0) { +		off = fdt_setprop_cell(blob, off, "clock-frequency", freq); +		if (off > 0) +			printf("WARNING enable to set clock-frequency " +				"for %s: %s\n", alias, fdt_strerror(off)); +	} +} + +static void ft_fixup_dpaa_clks(void *blob) +{ +	sys_info_t sysinfo; + +	get_sys_info(&sysinfo); +	ft_fixup_clks(blob, "fman0", sysinfo.freqFMan[0]); + +#if (CONFIG_SYS_NUM_FMAN == 2) +	ft_fixup_clks(blob, "fman1", sysinfo.freqFMan[1]); +#endif + +#ifdef CONFIG_SYS_DPAA_PME +	ft_fixup_clks(blob, "pme", sysinfo.freqPME); +#endif +} +#else +#define ft_fixup_dpaa_clks(x) +#endif + +#ifdef CONFIG_QE +static void ft_fixup_qe_snum(void *blob) +{ +	unsigned int svr; + +	svr = mfspr(SPRN_SVR); +	if (SVR_SOC_VER(svr) == SVR_8569_E) { +		if(IS_SVR_REV(svr, 1, 0)) +			do_fixup_by_compat_u32(blob, "fsl,qe", +				"fsl,qe-num-snums", 46, 1); +		else +			do_fixup_by_compat_u32(blob, "fsl,qe", +				"fsl,qe-num-snums", 76, 1); +	} +} +#endif + +void ft_cpu_setup(void *blob, bd_t *bd) +{ +	int off; +	int val; +	sys_info_t sysinfo; + +	/* delete crypto node if not on an E-processor */ +	if (!IS_E_PROCESSOR(get_svr())) +		fdt_fixup_crypto_node(blob, 0); + +	fdt_fixup_ethernet(blob); + +	fdt_add_enet_stashing(blob); + +	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4, +		"timebase-frequency", get_tbclk(), 1); +	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4, +		"bus-frequency", bd->bi_busfreq, 1); +	get_sys_info(&sysinfo); +	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); +	while (off != -FDT_ERR_NOTFOUND) { +		u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0); +		val = cpu_to_fdt32(sysinfo.freqProcessor[*reg]); +		fdt_setprop(blob, off, "clock-frequency", &val, 4); +		off = fdt_node_offset_by_prop_value(blob, off, "device_type", +							"cpu", 4); +	} +	do_fixup_by_prop_u32(blob, "device_type", "soc", 4, +		"bus-frequency", bd->bi_busfreq, 1); + +	do_fixup_by_compat_u32(blob, "fsl,pq3-localbus", +		"bus-frequency", gd->lbc_clk, 1); +	do_fixup_by_compat_u32(blob, "fsl,elbc", +		"bus-frequency", gd->lbc_clk, 1); +#ifdef CONFIG_QE +	ft_qe_setup(blob); +	ft_fixup_qe_snum(blob); +#endif + +#ifdef CONFIG_SYS_NS16550 +	do_fixup_by_compat_u32(blob, "ns16550", +		"clock-frequency", CONFIG_SYS_NS16550_CLK, 1); +#endif + +#ifdef CONFIG_CPM2 +	do_fixup_by_compat_u32(blob, "fsl,cpm2-scc-uart", +		"current-speed", bd->bi_baudrate, 1); + +	do_fixup_by_compat_u32(blob, "fsl,cpm2-brg", +		"clock-frequency", bd->bi_brgfreq, 1); +#endif + +	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize); + +#ifdef CONFIG_MP +	ft_fixup_cpu(blob, (u64)bd->bi_memstart + (u64)bd->bi_memsize); +#endif +	ft_fixup_num_cores(blob); + +	ft_fixup_cache(blob); + +#if defined(CONFIG_FSL_ESDHC) +	fdt_fixup_esdhc(blob, bd); +#endif + +	ft_fixup_dpaa_clks(blob); +} diff --git a/arch/powerpc/cpu/mpc85xx/fixed_ivor.S b/arch/powerpc/cpu/mpc85xx/fixed_ivor.S new file mode 100644 index 000000000..320cae329 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/fixed_ivor.S @@ -0,0 +1,79 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. + * + * Kumar Gala <kumar.gala@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 + */ + +/* This file is intended to be included by other asm code since + * we will want to execute this on both the primary core when + * it does a bootm and the secondary core's that get released + * out of the spin table */ + +#define SET_IVOR(vector_number, vector_offset)	\ +	li	r3,vector_offset@l; 		\ +	mtspr	SPRN_IVOR##vector_number,r3; + +#define SET_GIVOR(vector_number, vector_offset)	\ +	li	r3,vector_offset@l; 		\ +	mtspr	SPRN_GIVOR##vector_number,r3; + +	SET_IVOR(0, 0x020) /* Critical Input */ +	SET_IVOR(1, 0x000) /* Machine Check */ +	SET_IVOR(2, 0x060) /* Data Storage */ +	SET_IVOR(3, 0x080) /* Instruction Storage */ +	SET_IVOR(4, 0x0a0) /* External Input */ +	SET_IVOR(5, 0x0c0) /* Alignment */ +	SET_IVOR(6, 0x0e0) /* Program */ +	SET_IVOR(7, 0x100) /* FP Unavailable */ +	SET_IVOR(8, 0x120) /* System Call */ +	SET_IVOR(9, 0x140) /* Auxiliary Processor Unavailable */ +	SET_IVOR(10, 0x160) /* Decrementer */ +	SET_IVOR(11, 0x180) /* Fixed Interval Timer */ +	SET_IVOR(12, 0x1a0) /* Watchdog Timer */ +	SET_IVOR(13, 0x1c0) /* Data TLB Error */ +	SET_IVOR(14, 0x1e0) /* Instruction TLB Error */ +	SET_IVOR(15, 0x040) /* Debug */ + +/* e500v1 & e500v2 only */ +#ifndef CONFIG_E500MC +	SET_IVOR(32, 0x200) /* SPE Unavailable */ +	SET_IVOR(33, 0x220) /* Embedded FP Data */ +	SET_IVOR(34, 0x240) /* Embedded FP Round */ +#endif + +	SET_IVOR(35, 0x260) /* Performance monitor */ + +/* e500mc only */ +#ifdef CONFIG_E500MC +	SET_IVOR(36, 0x280) /* Processor doorbell */ +	SET_IVOR(37, 0x2a0) /* Processor doorbell critical */ +	SET_IVOR(38, 0x2c0) /* Guest Processor doorbell */ +	SET_IVOR(39, 0x2e0) /* Guest Processor critical & machine check */ +	SET_IVOR(40, 0x300) /* Hypervisor system call */ +	SET_IVOR(41, 0x320) /* Hypervisor Priviledge */ + +	SET_GIVOR(2, 0x060) /* Guest Data Storage */ +	SET_GIVOR(3, 0x080) /* Guest Instruction Storage */ +	SET_GIVOR(4, 0x0a0) /* Guest External Input */ +	SET_GIVOR(8, 0x120) /* Guest System Call */ +	SET_GIVOR(13, 0x1c0) /* Guest Data TLB Error */ +	SET_GIVOR(14, 0x1e0) /* Guest Instruction TLB Error */ +#endif diff --git a/arch/powerpc/cpu/mpc85xx/interrupts.c b/arch/powerpc/cpu/mpc85xx/interrupts.c new file mode 100644 index 000000000..409367d15 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/interrupts.c @@ -0,0 +1,110 @@ +/* + * (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) + * + * 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/processor.h> +#include <asm/io.h> + +int interrupt_init_cpu(unsigned int *decrementer_count) +{ +	ccsr_pic_t __iomem *pic = (void *)CONFIG_SYS_MPC85xx_PIC_ADDR; + +	out_be32(&pic->gcr, MPC85xx_PICGCR_RST); +	while (in_be32(&pic->gcr) & MPC85xx_PICGCR_RST) +		; +	out_be32(&pic->gcr, MPC85xx_PICGCR_M); +	in_be32(&pic->gcr); + +	*decrementer_count = get_tbclk() / CONFIG_SYS_HZ; + +	/* PIE is same as DIE, dec interrupt enable */ +	mtspr(SPRN_TCR, TCR_PIE); + +#ifdef CONFIG_INTERRUPTS +	pic->iivpr1 = 0x810001;	/* 50220 enable ecm interrupts */ +	debug("iivpr1@%x = %x\n", (uint)&pic->iivpr1, pic->iivpr1); + +	pic->iivpr2 = 0x810002;	/* 50240 enable ddr interrupts */ +	debug("iivpr2@%x = %x\n", (uint)&pic->iivpr2, pic->iivpr2); + +	pic->iivpr3 = 0x810003;	/* 50260 enable lbc interrupts */ +	debug("iivpr3@%x = %x\n", (uint)&pic->iivpr3, pic->iivpr3); + +#ifdef CONFIG_PCI1 +	pic->iivpr8 = 0x810008;	/* enable pci1 interrupts */ +	debug("iivpr8@%x = %x\n", (uint)&pic->iivpr8, pic->iivpr8); +#endif +#if defined(CONFIG_PCI2) || defined(CONFIG_PCIE2) +	pic->iivpr9 = 0x810009;	/* enable pci1 interrupts */ +	debug("iivpr9@%x = %x\n", (uint)&pic->iivpr9, pic->iivpr9); +#endif +#ifdef CONFIG_PCIE1 +	pic->iivpr10 = 0x81000a;	/* enable pcie1 interrupts */ +	debug("iivpr10@%x = %x\n", (uint)&pic->iivpr10, pic->iivpr10); +#endif +#ifdef CONFIG_PCIE3 +	pic->iivpr11 = 0x81000b;	/* enable pcie3 interrupts */ +	debug("iivpr11@%x = %x\n", (uint)&pic->iivpr11, pic->iivpr11); +#endif + +	pic->ctpr=0;		/* 40080 clear current task priority register */ +#endif + +	return (0); +} + +/* Install and free a interrupt handler. Not implemented yet. */ + +void +irq_install_handler(int vec, interrupt_handler_t *handler, void *arg) +{ +	return; +} + +void +irq_free_handler(int vec) +{ +	return; +} + +void timer_interrupt_cpu(struct pt_regs *regs) +{ +	/* PIS is same as DIS, dec interrupt status */ +	mtspr(SPRN_TSR, TSR_PIS); +} + +#if defined(CONFIG_CMD_IRQ) +/* irqinfo - print information about PCI devices,not implemented. */ +int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	return 0; +} +#endif diff --git a/arch/powerpc/cpu/mpc85xx/mp.c b/arch/powerpc/cpu/mpc85xx/mp.c new file mode 100644 index 000000000..826bf32d4 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/mp.c @@ -0,0 +1,355 @@ +/* + * Copyright 2008-2010 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/processor.h> +#include <ioports.h> +#include <lmb.h> +#include <asm/io.h> +#include <asm/mmu.h> +#include <asm/fsl_law.h> +#include "mp.h" + +DECLARE_GLOBAL_DATA_PTR; + +u32 get_my_id() +{ +	return mfspr(SPRN_PIR); +} + +int cpu_reset(int nr) +{ +	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR); +	out_be32(&pic->pir, 1 << nr); +	/* the dummy read works around an errata on early 85xx MP PICs */ +	(void)in_be32(&pic->pir); +	out_be32(&pic->pir, 0x0); + +	return 0; +} + +int cpu_status(int nr) +{ +	u32 *table, id = get_my_id(); + +	if (nr == id) { +		table = (u32 *)get_spin_virt_addr(); +		printf("table base @ 0x%p\n", table); +	} else { +		table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY; +		printf("Running on cpu %d\n", id); +		printf("\n"); +		printf("table @ 0x%p\n", table); +		printf("   addr - 0x%08x\n", table[BOOT_ENTRY_ADDR_LOWER]); +		printf("   pir  - 0x%08x\n", table[BOOT_ENTRY_PIR]); +		printf("   r3   - 0x%08x\n", table[BOOT_ENTRY_R3_LOWER]); +		printf("   r6   - 0x%08x\n", table[BOOT_ENTRY_R6_LOWER]); +	} + +	return 0; +} + +#ifdef CONFIG_FSL_CORENET +int cpu_disable(int nr) +{ +	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + +	setbits_be32(&gur->coredisrl, 1 << nr); + +	return 0; +} +#else +int cpu_disable(int nr) +{ +	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + +	switch (nr) { +	case 0: +		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU0); +		break; +	case 1: +		setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU1); +		break; +	default: +		printf("Invalid cpu number for disable %d\n", nr); +		return 1; +	} + +	return 0; +} +#endif + +static u8 boot_entry_map[4] = { +	0, +	BOOT_ENTRY_PIR, +	BOOT_ENTRY_R3_LOWER, +	BOOT_ENTRY_R6_LOWER, +}; + +int cpu_release(int nr, int argc, char *argv[]) +{ +	u32 i, val, *table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY; +	u64 boot_addr; + +	if (nr == get_my_id()) { +		printf("Invalid to release the boot core.\n\n"); +		return 1; +	} + +	if (argc != 4) { +		printf("Invalid number of arguments to release.\n\n"); +		return 1; +	} + +	boot_addr = simple_strtoull(argv[0], NULL, 16); + +	/* handle pir, r3, r6 */ +	for (i = 1; i < 4; i++) { +		if (argv[i][0] != '-') { +			u8 entry = boot_entry_map[i]; +			val = simple_strtoul(argv[i], NULL, 16); +			table[entry] = val; +		} +	} + +	table[BOOT_ENTRY_ADDR_UPPER] = (u32)(boot_addr >> 32); + +	/* ensure all table updates complete before final address write */ +	eieio(); + +	table[BOOT_ENTRY_ADDR_LOWER] = (u32)(boot_addr & 0xffffffff); + +	return 0; +} + +u32 determine_mp_bootpg(void) +{ +	/* if we have 4G or more of memory, put the boot page at 4Gb-4k */ +	if ((u64)gd->ram_size > 0xfffff000) +		return (0xfffff000); + +	return (gd->ram_size - 4096); +} + +ulong get_spin_phys_addr(void) +{ +	extern ulong __secondary_start_page; +	extern ulong __spin_table; + +	return (determine_mp_bootpg() + +		(ulong)&__spin_table - (ulong)&__secondary_start_page); +} + +ulong get_spin_virt_addr(void) +{ +	extern ulong __secondary_start_page; +	extern ulong __spin_table; + +	return (CONFIG_BPTR_VIRT_ADDR + +		(ulong)&__spin_table - (ulong)&__secondary_start_page); +} + +#ifdef CONFIG_FSL_CORENET +static void plat_mp_up(unsigned long bootpg) +{ +	u32 up, cpu_up_mask, whoami; +	u32 *table = (u32 *)get_spin_virt_addr(); +	volatile ccsr_gur_t *gur; +	volatile ccsr_local_t *ccm; +	volatile ccsr_rcpm_t *rcpm; +	volatile ccsr_pic_t *pic; +	int timeout = 10; +	u32 nr_cpus; +	struct law_entry e; + +	gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +	ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR); +	rcpm = (void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR); +	pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR); + +	nr_cpus = ((in_be32(&pic->frr) >> 8) & 0xff) + 1; + +	whoami = in_be32(&pic->whoami); +	cpu_up_mask = 1 << whoami; +	out_be32(&ccm->bstrl, bootpg); + +	e = find_law(bootpg); +	out_be32(&ccm->bstrar, LAW_EN | e.trgt_id << 20 | LAW_SIZE_4K); + +	/* readback to sync write */ +	in_be32(&ccm->bstrar); + +	/* disable time base at the platform */ +	out_be32(&rcpm->ctbenrl, cpu_up_mask); + +	/* release the hounds */ +	up = ((1 << nr_cpus) - 1); +	out_be32(&gur->brrl, up); + +	/* wait for everyone */ +	while (timeout) { +		int i; +		for (i = 0; i < nr_cpus; i++) { +			if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER]) +				cpu_up_mask |= (1 << i); +		}; + +		if ((cpu_up_mask & up) == up) +			break; + +		udelay(100); +		timeout--; +	} + +	if (timeout == 0) +		printf("CPU up timeout. CPU up mask is %x should be %x\n", +			cpu_up_mask, up); + +	/* enable time base at the platform */ +	out_be32(&rcpm->ctbenrl, 0); +	mtspr(SPRN_TBWU, 0); +	mtspr(SPRN_TBWL, 0); +	out_be32(&rcpm->ctbenrl, (1 << nr_cpus) - 1); + +#ifdef CONFIG_MPC8xxx_DISABLE_BPTR +	/* +	 * Disabling Boot Page Translation allows the memory region 0xfffff000 +	 * to 0xffffffff to be used normally.  Leaving Boot Page Translation +	 * enabled remaps 0xfffff000 to SDRAM which makes that memory region +	 * unusable for normal operation but it does allow OSes to easily +	 * reset a processor core to put it back into U-Boot's spinloop. +	 */ +	clrbits_be32(&ecm->bptr, 0x80000000); +#endif +} +#else +static void plat_mp_up(unsigned long bootpg) +{ +	u32 up, cpu_up_mask, whoami; +	u32 *table = (u32 *)get_spin_virt_addr(); +	volatile u32 bpcr; +	volatile ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR); +	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR); +	u32 devdisr; +	int timeout = 10; + +	whoami = in_be32(&pic->whoami); +	out_be32(&ecm->bptr, 0x80000000 | (bootpg >> 12)); + +	/* disable time base at the platform */ +	devdisr = in_be32(&gur->devdisr); +	if (whoami) +		devdisr |= MPC85xx_DEVDISR_TB0; +	else +		devdisr |= MPC85xx_DEVDISR_TB1; +	out_be32(&gur->devdisr, devdisr); + +	/* release the hounds */ +	up = ((1 << cpu_numcores()) - 1); +	bpcr = in_be32(&ecm->eebpcr); +	bpcr |= (up << 24); +	out_be32(&ecm->eebpcr, bpcr); +	asm("sync; isync; msync"); + +	cpu_up_mask = 1 << whoami; +	/* wait for everyone */ +	while (timeout) { +		int i; +		for (i = 0; i < cpu_numcores(); i++) { +			if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER]) +				cpu_up_mask |= (1 << i); +		}; + +		if ((cpu_up_mask & up) == up) +			break; + +		udelay(100); +		timeout--; +	} + +	if (timeout == 0) +		printf("CPU up timeout. CPU up mask is %x should be %x\n", +			cpu_up_mask, up); + +	/* enable time base at the platform */ +	if (whoami) +		devdisr |= MPC85xx_DEVDISR_TB1; +	else +		devdisr |= MPC85xx_DEVDISR_TB0; +	out_be32(&gur->devdisr, devdisr); +	mtspr(SPRN_TBWU, 0); +	mtspr(SPRN_TBWL, 0); + +	devdisr &= ~(MPC85xx_DEVDISR_TB0 | MPC85xx_DEVDISR_TB1); +	out_be32(&gur->devdisr, devdisr); + +#ifdef CONFIG_MPC8xxx_DISABLE_BPTR +	/* +	 * Disabling Boot Page Translation allows the memory region 0xfffff000 +	 * to 0xffffffff to be used normally.  Leaving Boot Page Translation +	 * enabled remaps 0xfffff000 to SDRAM which makes that memory region +	 * unusable for normal operation but it does allow OSes to easily +	 * reset a processor core to put it back into U-Boot's spinloop. +	 */ +	clrbits_be32(&ecm->bptr, 0x80000000); +#endif +} +#endif + +void cpu_mp_lmb_reserve(struct lmb *lmb) +{ +	u32 bootpg = determine_mp_bootpg(); + +	lmb_reserve(lmb, bootpg, 4096); +} + +void setup_mp(void) +{ +	extern ulong __secondary_start_page; +	extern ulong __bootpg_addr; +	ulong fixup = (ulong)&__secondary_start_page; +	u32 bootpg = determine_mp_bootpg(); + +	/* Store the bootpg's SDRAM address for use by secondary CPU cores */ +	__bootpg_addr = bootpg; + +	/* look for the tlb covering the reset page, there better be one */ +	int i = find_tlb_idx((void *)CONFIG_BPTR_VIRT_ADDR, 1); + +	/* we found a match */ +	if (i != -1) { +		/* map reset page to bootpg so we can copy code there */ +		disable_tlb(i); + +		set_tlb(1, CONFIG_BPTR_VIRT_ADDR, bootpg, /* tlb, epn, rpn */ +			MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, /* perms, wimge */ +			0, i, BOOKE_PAGESZ_4K, 1); /* ts, esel, tsize, iprot */ + +		memcpy((void *)CONFIG_BPTR_VIRT_ADDR, (void *)fixup, 4096); + +		plat_mp_up(bootpg); +	} else { +		puts("WARNING: No reset page TLB. " +			"Skipping secondary core setup\n"); +	} +} diff --git a/arch/powerpc/cpu/mpc85xx/mp.h b/arch/powerpc/cpu/mpc85xx/mp.h new file mode 100644 index 000000000..3422cc107 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/mp.h @@ -0,0 +1,21 @@ +#ifndef __MPC85XX_MP_H_ +#define __MPC85XX_MP_H_ + +#include <asm/mp.h> + +ulong get_spin_phys_addr(void); +ulong get_spin_virt_addr(void); +u32 get_my_id(void); + +#define BOOT_ENTRY_ADDR_UPPER	0 +#define BOOT_ENTRY_ADDR_LOWER	1 +#define BOOT_ENTRY_R3_UPPER	2 +#define BOOT_ENTRY_R3_LOWER	3 +#define BOOT_ENTRY_RESV		4 +#define BOOT_ENTRY_PIR		5 +#define BOOT_ENTRY_R6_UPPER	6 +#define BOOT_ENTRY_R6_LOWER	7 +#define NUM_BOOT_ENTRY		8 +#define SIZE_BOOT_ENTRY		(NUM_BOOT_ENTRY * sizeof(u32)) + +#endif diff --git a/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c new file mode 100644 index 000000000..cb6a6f00c --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2008 Freescale Semicondutor, Inc. + *	Dave Liu <daveliu@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. + */ + +#include <config.h> +#include <common.h> +#include <asm/io.h> +#include <asm/immap_85xx.h> + +/* PORDEVSR register */ +#define GUTS_PORDEVSR_OFFS		0xc +#define GUTS_PORDEVSR_SERDES2_IO_SEL	0x38000000 +#define GUTS_PORDEVSR_SERDES2_IO_SEL_SHIFT	27 + +/* SerDes CR0 register */ +#define	FSL_SRDSCR0_OFFS	0x0 +#define FSL_SRDSCR0_TXEQA_MASK	0x00007000 +#define FSL_SRDSCR0_TXEQA_SGMII	0x00004000 +#define FSL_SRDSCR0_TXEQA_SATA	0x00001000 +#define FSL_SRDSCR0_TXEQE_MASK	0x00000700 +#define FSL_SRDSCR0_TXEQE_SGMII	0x00000400 +#define FSL_SRDSCR0_TXEQE_SATA	0x00000100 + +/* SerDes CR1 register */ +#define FSL_SRDSCR1_OFFS	0x4 +#define FSL_SRDSCR1_LANEA_MASK	0x80200000 +#define FSL_SRDSCR1_LANEA_OFF	0x80200000 +#define FSL_SRDSCR1_LANEE_MASK	0x08020000 +#define FSL_SRDSCR1_LANEE_OFF	0x08020000 + +/* SerDes CR2 register */ +#define FSL_SRDSCR2_OFFS	0x8 +#define FSL_SRDSCR2_EICA_MASK	0x00001f00 +#define FSL_SRDSCR2_EICA_SGMII	0x00000400 +#define FSL_SRDSCR2_EICA_SATA	0x00001400 +#define FSL_SRDSCR2_EICE_MASK	0x0000001f +#define FSL_SRDSCR2_EICE_SGMII	0x00000004 +#define FSL_SRDSCR2_EICE_SATA	0x00000014 + +/* SerDes CR3 register */ +#define FSL_SRDSCR3_OFFS	0xc +#define FSL_SRDSCR3_LANEA_MASK	0x3f000700 +#define FSL_SRDSCR3_LANEA_SGMII	0x00000000 +#define FSL_SRDSCR3_LANEA_SATA	0x15000500 +#define FSL_SRDSCR3_LANEE_MASK	0x003f0007 +#define FSL_SRDSCR3_LANEE_SGMII	0x00000000 +#define FSL_SRDSCR3_LANEE_SATA	0x00150005 + +void fsl_serdes_init(void) +{ +	void *guts = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +	void *sd = (void *)CONFIG_SYS_MPC85xx_SERDES2_ADDR; +	u32 pordevsr = in_be32(guts + GUTS_PORDEVSR_OFFS); +	u32 srds2_io_sel; +	u32 tmp; + +	/* parse the SRDS2_IO_SEL of PORDEVSR */ +	srds2_io_sel = (pordevsr & GUTS_PORDEVSR_SERDES2_IO_SEL) +		       >> GUTS_PORDEVSR_SERDES2_IO_SEL_SHIFT; + +	switch (srds2_io_sel) { +	case 1:	/* Lane A - SATA1, Lane E - SATA2 */ +		/* CR 0 */ +		tmp = in_be32(sd + FSL_SRDSCR0_OFFS); +		tmp &= ~FSL_SRDSCR0_TXEQA_MASK; +		tmp |= FSL_SRDSCR0_TXEQA_SATA; +		tmp &= ~FSL_SRDSCR0_TXEQE_MASK; +		tmp |= FSL_SRDSCR0_TXEQE_SATA; +		out_be32(sd + FSL_SRDSCR0_OFFS, tmp); +		/* CR 1 */ +		tmp = in_be32(sd + FSL_SRDSCR1_OFFS); +		tmp &= ~FSL_SRDSCR1_LANEA_MASK; +		tmp &= ~FSL_SRDSCR1_LANEE_MASK; +		out_be32(sd + FSL_SRDSCR1_OFFS, tmp); +		/* CR 2 */ +		tmp = in_be32(sd + FSL_SRDSCR2_OFFS); +		tmp &= ~FSL_SRDSCR2_EICA_MASK; +		tmp |= FSL_SRDSCR2_EICA_SATA; +		tmp &= ~FSL_SRDSCR2_EICE_MASK; +		tmp |= FSL_SRDSCR2_EICE_SATA; +		out_be32(sd + FSL_SRDSCR2_OFFS, tmp); +		/* CR 3 */ +		tmp = in_be32(sd + FSL_SRDSCR3_OFFS); +		tmp &= ~FSL_SRDSCR3_LANEA_MASK; +		tmp |= FSL_SRDSCR3_LANEA_SATA; +		tmp &= ~FSL_SRDSCR3_LANEE_MASK; +		tmp |= FSL_SRDSCR3_LANEE_SATA; +		out_be32(sd + FSL_SRDSCR3_OFFS, tmp); +		break; +	case 3: /* Lane A - SATA1, Lane E - disabled */ +		/* CR 0 */ +		tmp = in_be32(sd + FSL_SRDSCR0_OFFS); +		tmp &= ~FSL_SRDSCR0_TXEQA_MASK; +		tmp |= FSL_SRDSCR0_TXEQA_SATA; +		out_be32(sd + FSL_SRDSCR0_OFFS, tmp); +		/* CR 1 */ +		tmp = in_be32(sd + FSL_SRDSCR1_OFFS); +		tmp &= ~FSL_SRDSCR1_LANEE_MASK; +		tmp |= FSL_SRDSCR1_LANEE_OFF; +		out_be32(sd + FSL_SRDSCR1_OFFS, tmp); +		/* CR 2 */ +		tmp = in_be32(sd + FSL_SRDSCR2_OFFS); +		tmp &= ~FSL_SRDSCR2_EICA_MASK; +		tmp |= FSL_SRDSCR2_EICA_SATA; +		out_be32(sd + FSL_SRDSCR2_OFFS, tmp); +		/* CR 3 */ +		tmp = in_be32(sd + FSL_SRDSCR3_OFFS); +		tmp &= ~FSL_SRDSCR3_LANEA_MASK; +		tmp |= FSL_SRDSCR3_LANEA_SATA; +		out_be32(sd + FSL_SRDSCR3_OFFS, tmp); +		break; +	case 4: /* Lane A - eTSEC1 SGMII, Lane E - eTSEC3 SGMII */ +		/* CR 0 */ +		tmp = in_be32(sd + FSL_SRDSCR0_OFFS); +		tmp &= ~FSL_SRDSCR0_TXEQA_MASK; +		tmp |= FSL_SRDSCR0_TXEQA_SGMII; +		tmp &= ~FSL_SRDSCR0_TXEQE_MASK; +		tmp |= FSL_SRDSCR0_TXEQE_SGMII; +		out_be32(sd + FSL_SRDSCR0_OFFS, tmp); +		/* CR 1 */ +		tmp = in_be32(sd + FSL_SRDSCR1_OFFS); +		tmp &= ~FSL_SRDSCR1_LANEA_MASK; +		tmp &= ~FSL_SRDSCR1_LANEE_MASK; +		out_be32(sd + FSL_SRDSCR1_OFFS, tmp); +		/* CR 2 */ +		tmp = in_be32(sd + FSL_SRDSCR2_OFFS); +		tmp &= ~FSL_SRDSCR2_EICA_MASK; +		tmp |= FSL_SRDSCR2_EICA_SGMII; +		tmp &= ~FSL_SRDSCR2_EICE_MASK; +		tmp |= FSL_SRDSCR2_EICE_SGMII; +		out_be32(sd + FSL_SRDSCR2_OFFS, tmp); +		/* CR 3 */ +		tmp = in_be32(sd + FSL_SRDSCR3_OFFS); +		tmp &= ~FSL_SRDSCR3_LANEA_MASK; +		tmp |= FSL_SRDSCR3_LANEA_SGMII; +		tmp &= ~FSL_SRDSCR3_LANEE_MASK; +		tmp |= FSL_SRDSCR3_LANEE_SGMII; +		out_be32(sd + FSL_SRDSCR3_OFFS, tmp); +		break; +	case 6: /* Lane A - eTSEC1 SGMII, Lane E - disabled */ +		/* CR 0 */ +		tmp = in_be32(sd + FSL_SRDSCR0_OFFS); +		tmp &= ~FSL_SRDSCR0_TXEQA_MASK; +		tmp |= FSL_SRDSCR0_TXEQA_SGMII; +		out_be32(sd + FSL_SRDSCR0_OFFS, tmp); +		/* CR 1 */ +		tmp = in_be32(sd + FSL_SRDSCR1_OFFS); +		tmp &= ~FSL_SRDSCR1_LANEE_MASK; +		tmp |= FSL_SRDSCR1_LANEE_OFF; +		out_be32(sd + FSL_SRDSCR1_OFFS, tmp); +		/* CR 2 */ +		tmp = in_be32(sd + FSL_SRDSCR2_OFFS); +		tmp &= ~FSL_SRDSCR2_EICA_MASK; +		tmp |= FSL_SRDSCR2_EICA_SGMII; +		out_be32(sd + FSL_SRDSCR2_OFFS, tmp); +		/* CR 3 */ +		tmp = in_be32(sd + FSL_SRDSCR3_OFFS); +		tmp &= ~FSL_SRDSCR3_LANEA_MASK; +		tmp |= FSL_SRDSCR3_LANEA_SGMII; +		out_be32(sd + FSL_SRDSCR3_OFFS, tmp); +		break; +	case 7: /* Lane A - disabled, Lane E - disabled */ +		/* CR 1 */ +		tmp = in_be32(sd + FSL_SRDSCR1_OFFS); +		tmp &= ~FSL_SRDSCR1_LANEA_MASK; +		tmp |= FSL_SRDSCR1_LANEA_OFF; +		tmp &= ~FSL_SRDSCR1_LANEE_MASK; +		tmp |= FSL_SRDSCR1_LANEE_OFF; +		out_be32(sd + FSL_SRDSCR1_OFFS, tmp); +		break; +	default: +		break; +	} +} diff --git a/arch/powerpc/cpu/mpc85xx/pci.c b/arch/powerpc/cpu/mpc85xx/pci.c new file mode 100644 index 000000000..75d2716ef --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/pci.c @@ -0,0 +1,230 @@ +/* + * Copyright 2004 Freescale Semiconductor. + * Copyright (C) 2003 Motorola Inc. + * Xianghua Xiao (x.xiao@motorola.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * PCI Configuration space access support for MPC85xx PCI Bridge + */ +#include <common.h> +#include <asm/cpm_85xx.h> +#include <pci.h> + +#if !defined(CONFIG_FSL_PCI_INIT) + +#ifndef CONFIG_SYS_PCI1_MEM_BUS +#define CONFIG_SYS_PCI1_MEM_BUS CONFIG_SYS_PCI1_MEM_BASE +#endif + +#ifndef CONFIG_SYS_PCI1_IO_BUS +#define CONFIG_SYS_PCI1_IO_BUS CONFIG_SYS_PCI1_IO_BASE +#endif + +#ifndef CONFIG_SYS_PCI2_MEM_BUS +#define CONFIG_SYS_PCI2_MEM_BUS CONFIG_SYS_PCI2_MEM_BASE +#endif + +#ifndef CONFIG_SYS_PCI2_IO_BUS +#define CONFIG_SYS_PCI2_IO_BUS CONFIG_SYS_PCI2_IO_BASE +#endif + +static struct pci_controller *pci_hose; + +void +pci_mpc85xx_init(struct pci_controller *board_hose) +{ +	u16 reg16; +	u32 dev; + +	volatile ccsr_pcix_t *pcix = (void *)(CONFIG_SYS_MPC85xx_PCIX_ADDR); +#ifdef CONFIG_MPC85XX_PCI2 +	volatile ccsr_pcix_t *pcix2 = (void *)(CONFIG_SYS_MPC85xx_PCIX2_ADDR); +#endif +	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +	struct pci_controller * hose; + +	pci_hose = board_hose; + +	hose = &pci_hose[0]; + +	hose->first_busno = 0; +	hose->last_busno = 0xff; + +	pci_setup_indirect(hose, +			   (CONFIG_SYS_IMMR+0x8000), +			   (CONFIG_SYS_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 & MPC85xx_PORDEVSR_PCI1)) { +		/* 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   = (CONFIG_SYS_PCI1_MEM_BUS >> 12) & 0x000fffff; +	pcix->potear1  = 0x00000000; +	pcix->powbar1  = (CONFIG_SYS_PCI1_MEM_PHYS >> 12) & 0x000fffff; +	pcix->powbear1 = 0x00000000; +	pcix->powar1 = (POWAR_EN | POWAR_MEM_READ | +			POWAR_MEM_WRITE | (__ilog2(CONFIG_SYS_PCI1_MEM_SIZE) - 1)); + +	pcix->potar2  = (CONFIG_SYS_PCI1_IO_BUS >> 12) & 0x000fffff; +	pcix->potear2  = 0x00000000; +	pcix->powbar2  = (CONFIG_SYS_PCI1_IO_PHYS >> 12) & 0x000fffff; +	pcix->powbear2 = 0x00000000; +	pcix->powar2 = (POWAR_EN | POWAR_IO_READ | +			POWAR_IO_WRITE | (__ilog2(CONFIG_SYS_PCI1_IO_SIZE) - 1)); + +	pcix->pitar1 = 0x00000000; +	pcix->piwbar1 = 0x00000000; +	pcix->piwar1 = (PIWAR_EN | PIWAR_PF | PIWAR_LOCAL | +			PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_MEM_2G); + +	pcix->powar3 = 0; +	pcix->powar4 = 0; +	pcix->piwar2 = 0; +	pcix->piwar3 = 0; + +	pci_set_region(hose->regions + 0, +		       CONFIG_SYS_PCI1_MEM_BUS, +		       CONFIG_SYS_PCI1_MEM_PHYS, +		       CONFIG_SYS_PCI1_MEM_SIZE, +		       PCI_REGION_MEM); + +	pci_set_region(hose->regions + 1, +		       CONFIG_SYS_PCI1_IO_BUS, +		       CONFIG_SYS_PCI1_IO_PHYS, +		       CONFIG_SYS_PCI1_IO_SIZE, +		       PCI_REGION_IO); + +	hose->region_count = 2; + +	pci_register_hose(hose); + +#if defined(CONFIG_MPC8555CDS) || defined(CONFIG_MPC8541CDS) +	/* +	 * This is a SW workaround for an apparent HW problem +	 * in the PCI controller on the MPC85555/41 CDS boards. +	 * The first config cycle must be to a valid, known +	 * device on the PCI bus in order to trick the PCI +	 * controller state machine into a known valid state. +	 * Without this, the first config cycle has the chance +	 * of hanging the controller permanently, just leaving +	 * it in a semi-working state, or leaving it working. +	 * +	 * Pick on the Tundra, Device 17, to get it right. +	 */ +	{ +		u8 header_type; + +		pci_hose_read_config_byte(hose, +					  PCI_BDF(0,BRIDGE_ID,0), +					  PCI_HEADER_TYPE, +					  &header_type); +	} +#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, +			   (CONFIG_SYS_IMMR+0x9000), +			   (CONFIG_SYS_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   = (CONFIG_SYS_PCI2_MEM_BUS >> 12) & 0x000fffff; +	pcix2->potear1  = 0x00000000; +	pcix2->powbar1  = (CONFIG_SYS_PCI2_MEM_PHYS >> 12) & 0x000fffff; +	pcix2->powbear1 = 0x00000000; +	pcix2->powar1 = (POWAR_EN | POWAR_MEM_READ | +			POWAR_MEM_WRITE | (__ilog2(CONFIG_SYS_PCI2_MEM_SIZE) - 1)); + +	pcix2->potar2  = (CONFIG_SYS_PCI2_IO_BUS >> 12) & 0x000fffff; +	pcix2->potear2  = 0x00000000; +	pcix2->powbar2  = (CONFIG_SYS_PCI2_IO_PHYS >> 12) & 0x000fffff; +	pcix2->powbear2 = 0x00000000; +	pcix2->powar2 = (POWAR_EN | POWAR_IO_READ | +			POWAR_IO_WRITE | (__ilog2(CONFIG_SYS_PCI2_IO_SIZE) - 1)); + +	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, +		       CONFIG_SYS_PCI2_MEM_BUS, +		       CONFIG_SYS_PCI2_MEM_PHYS, +		       CONFIG_SYS_PCI2_MEM_SIZE, +		       PCI_REGION_MEM); + +	pci_set_region(hose->regions + 1, +		       CONFIG_SYS_PCI2_IO_BUS, +		       CONFIG_SYS_PCI2_IO_PHYS, +		       CONFIG_SYS_PCI2_IO_SIZE, +		       PCI_REGION_IO); + +	hose->region_count = 2; + +	/* +	 * Hose scan. +	 */ +	pci_register_hose(hose); + +	hose->last_busno = pci_hose_scan(hose); +#endif +} +#endif /* !CONFIG_FSL_PCI_INIT */ diff --git a/arch/powerpc/cpu/mpc85xx/qe_io.c b/arch/powerpc/cpu/mpc85xx/qe_io.c new file mode 100644 index 000000000..72a29b7b5 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/qe_io.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu <daveliu@freescale.com> + * based on source code of Shlomi Gridish + * + * 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/immap_85xx.h" + +#if defined(CONFIG_QE) +#define	NUM_OF_PINS	32 +void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign) +{ +	u32			pin_2bit_mask; +	u32			pin_2bit_dir; +	u32			pin_2bit_assign; +	u32			pin_1bit_mask; +	u32			tmp_val; +	volatile ccsr_gur_t	*gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +	volatile par_io_t	*par_io = (volatile par_io_t *) +						&(gur->qe_par_io); + +	/* Caculate pin location and 2bit mask and dir */ +	pin_2bit_mask = (u32)(0x3 << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2)); +	pin_2bit_dir = (u32)(dir << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2)); + +	/* Setup the direction */ +	tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? \ +		in_be32(&par_io[port].cpdir2) : +		in_be32(&par_io[port].cpdir1); + +	if (pin > (NUM_OF_PINS/2) -1) { +		out_be32(&par_io[port].cpdir2, ~pin_2bit_mask & tmp_val); +		out_be32(&par_io[port].cpdir2, pin_2bit_dir | tmp_val); +	} else { +		out_be32(&par_io[port].cpdir1, ~pin_2bit_mask & tmp_val); +		out_be32(&par_io[port].cpdir1, pin_2bit_dir | tmp_val); +	} + +	/* Calculate pin location for 1bit mask */ +	pin_1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin+1))); + +	/* Setup the open drain */ +	tmp_val = in_be32(&par_io[port].cpodr); +	if (open_drain) +		out_be32(&par_io[port].cpodr, pin_1bit_mask | tmp_val); +	else +		out_be32(&par_io[port].cpodr, ~pin_1bit_mask & tmp_val); + +	/* Setup the assignment */ +	tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? +		in_be32(&par_io[port].cppar2): +		in_be32(&par_io[port].cppar1); +	pin_2bit_assign = (u32)(assign +				<< (NUM_OF_PINS - (pin%(NUM_OF_PINS/2)+1)*2)); + +	/* Clear and set 2 bits mask */ +	if (pin > (NUM_OF_PINS/2) - 1) { +		out_be32(&par_io[port].cppar2, ~pin_2bit_mask & tmp_val); +		out_be32(&par_io[port].cppar2, pin_2bit_assign | tmp_val); +	} else { +		out_be32(&par_io[port].cppar1, ~pin_2bit_mask & tmp_val); +		out_be32(&par_io[port].cppar1, pin_2bit_assign | tmp_val); +	} +} + +#endif /* CONFIG_QE */ diff --git a/arch/powerpc/cpu/mpc85xx/release.S b/arch/powerpc/cpu/mpc85xx/release.S new file mode 100644 index 000000000..0b5b9da03 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/release.S @@ -0,0 +1,311 @@ +/* + * Copyright 2008-2010 Freescale Semiconductor, Inc. + * Kumar Gala <kumar.gala@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 <config.h> +#include <mpc85xx.h> +#include <version.h> + +#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file	*/ + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +#include <asm/cache.h> +#include <asm/mmu.h> + +/* To boot secondary cpus, we need a place for them to start up. + * Normally, they start at 0xfffffffc, but that's usually the + * firmware, and we don't want to have to run the firmware again. + * Instead, the primary cpu will set the BPTR to point here to + * this page.  We then set up the core, and head to + * start_secondary.  Note that this means that the code below + * must never exceed 1023 instructions (the branch at the end + * would then be the 1024th). + */ +	.globl	__secondary_start_page +	.align	12 +__secondary_start_page: +/* First do some preliminary setup */ +	lis	r3, HID0_EMCP@h		/* enable machine check */ +#ifndef CONFIG_E500MC +	ori	r3,r3,HID0_TBEN@l	/* enable Timebase */ +#endif +#ifdef CONFIG_PHYS_64BIT +	ori	r3,r3,HID0_ENMAS7@l	/* enable MAS7 updates */ +#endif +	mtspr	SPRN_HID0,r3 + +#ifndef CONFIG_E500MC +	li	r3,(HID1_ASTME|HID1_ABE)@l	/* Addr streaming & broadcast */ +	mfspr   r0,PVR +	andi.	r0,r0,0xff +	cmpwi	r0,0x50@l	/* if we are rev 5.0 or greater set MBDD */ +	blt 1f +	/* Set MBDD bit also */ +	ori r3, r3, HID1_MBDD@l +1: +	mtspr	SPRN_HID1,r3 +#endif + +	/* Enable branch prediction */ +	lis	r3,BUCSR_ENABLE@h +	ori	r3,r3,BUCSR_ENABLE@l +	mtspr	SPRN_BUCSR,r3 + +	/* Ensure TB is 0 */ +	li	r3,0 +	mttbl	r3 +	mttbu	r3 + +	/* Enable/invalidate the I-Cache */ +	lis	r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@h +	ori	r2,r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@l +	mtspr	SPRN_L1CSR1,r2 +1: +	mfspr	r3,SPRN_L1CSR1 +	and.	r1,r3,r2 +	bne	1b + +	lis	r3,(L1CSR1_CPE|L1CSR1_ICE)@h +	ori	r3,r3,(L1CSR1_CPE|L1CSR1_ICE)@l +	mtspr	SPRN_L1CSR1,r3 +	isync +2: +	mfspr	r3,SPRN_L1CSR1 +	andi.	r1,r3,L1CSR1_ICE@l +	beq	2b + +	/* Enable/invalidate the D-Cache */ +	lis	r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@h +	ori	r2,r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@l +	mtspr	SPRN_L1CSR0,r2 +1: +	mfspr	r3,SPRN_L1CSR0 +	and.	r1,r3,r2 +	bne	1b + +	lis	r3,(L1CSR0_CPE|L1CSR0_DCE)@h +	ori	r3,r3,(L1CSR0_CPE|L1CSR0_DCE)@l +	mtspr	SPRN_L1CSR0,r3 +	isync +2: +	mfspr	r3,SPRN_L1CSR0 +	andi.	r1,r3,L1CSR0_DCE@l +	beq	2b + +#define toreset(x) (x - __secondary_start_page + 0xfffff000) + +	/* get our PIR to figure out our table entry */ +	lis	r3,toreset(__spin_table)@h +	ori	r3,r3,toreset(__spin_table)@l + +	/* r10 has the base address for the entry */ +	mfspr	r0,SPRN_PIR +#ifdef CONFIG_E500MC +	rlwinm	r4,r0,27,27,31 +#else +	mr	r4,r0 +#endif +	slwi	r8,r4,5 +	add	r10,r3,r8 + +#if defined(CONFIG_E500MC) && defined(CONFIG_SYS_CACHE_STASHING) +	/* set stash id to (coreID) * 2 + 32 + L1 CT (0) */ +	slwi	r8,r4,1 +	addi	r8,r8,32 +	mtspr	L1CSR2,r8 +#endif + +#ifdef CONFIG_BACKSIDE_L2_CACHE +	/* Enable/invalidate the L2 cache */ +	msync +	lis	r2,(L2CSR0_L2FI|L2CSR0_L2LFC)@h +	ori	r2,r2,(L2CSR0_L2FI|L2CSR0_L2LFC)@l +	mtspr	SPRN_L2CSR0,r2 +1: +	mfspr	r3,SPRN_L2CSR0 +	and.	r1,r3,r2 +	bne	1b + +#ifdef CONFIG_SYS_CACHE_STASHING +	/* set stash id to (coreID) * 2 + 32 + L2 (1) */ +	addi	r3,r8,1 +	mtspr	SPRN_L2CSR1,r3 +#endif + +	lis	r3,CONFIG_SYS_INIT_L2CSR0@h +	ori	r3,r3,CONFIG_SYS_INIT_L2CSR0@l +	mtspr	SPRN_L2CSR0,r3 +	isync +2: +	mfspr	r3,SPRN_L2CSR0 +	andis.	r1,r3,L2CSR0_L2E@h +	beq	2b +#endif + +#define EPAPR_MAGIC		(0x45504150) +#define ENTRY_ADDR_UPPER	0 +#define ENTRY_ADDR_LOWER	4 +#define ENTRY_R3_UPPER		8 +#define ENTRY_R3_LOWER		12 +#define ENTRY_RESV		16 +#define ENTRY_PIR		20 +#define ENTRY_R6_UPPER		24 +#define ENTRY_R6_LOWER		28 +#define ENTRY_SIZE		32 + +	/* setup the entry */ +	li	r3,0 +	li	r8,1 +	stw	r0,ENTRY_PIR(r10) +	stw	r3,ENTRY_ADDR_UPPER(r10) +	stw	r8,ENTRY_ADDR_LOWER(r10) +	stw	r3,ENTRY_R3_UPPER(r10) +	stw	r4,ENTRY_R3_LOWER(r10) +	stw	r3,ENTRY_R6_UPPER(r10) +	stw	r3,ENTRY_R6_LOWER(r10) + +	/* load r13 with the address of the 'bootpg' in SDRAM */ +	lis	r13,toreset(__bootpg_addr)@h +	ori	r13,r13,toreset(__bootpg_addr)@l +	lwz	r13,0(r13) + +	/* setup mapping for AS = 1, and jump there */ +	lis	r11,(MAS0_TLBSEL(1)|MAS0_ESEL(1))@h +	mtspr	SPRN_MAS0,r11 +	lis	r11,(MAS1_VALID|MAS1_IPROT)@h +	ori	r11,r11,(MAS1_TS|MAS1_TSIZE(BOOKE_PAGESZ_4K))@l +	mtspr	SPRN_MAS1,r11 +	oris	r11,r13,(MAS2_I|MAS2_G)@h +	ori	r11,r13,(MAS2_I|MAS2_G)@l +	mtspr	SPRN_MAS2,r11 +	oris	r11,r13,(MAS3_SX|MAS3_SW|MAS3_SR)@h +	ori	r11,r13,(MAS3_SX|MAS3_SW|MAS3_SR)@l +	mtspr	SPRN_MAS3,r11 +	tlbwe + +	bl	1f +1:	mflr	r11 +	/* +	 * OR in 0xfff to create a mask of the bootpg SDRAM address.  We use +	 * this mask to fixup the cpu spin table and the address that we want +	 * to jump to, eg change them from 0xfffffxxx to 0x7ffffxxx if the +	 * bootpg is at 0x7ffff000 in SDRAM. +	 */ +	ori	r13,r13,0xfff +	and	r11, r11, r13 +	and	r10, r10, r13 + +	addi	r11,r11,(2f-1b) +	mfmsr	r13 +	ori	r12,r13,MSR_IS|MSR_DS@l + +	mtspr	SPRN_SRR0,r11 +	mtspr	SPRN_SRR1,r12 +	rfi + +	/* spin waiting for addr */ +2: +	lwz	r4,ENTRY_ADDR_LOWER(r10) +	andi.	r11,r4,1 +	bne	2b +	isync + +	/* setup IVORs to match fixed offsets */ +#include "fixed_ivor.S" + +	/* get the upper bits of the addr */ +	lwz	r11,ENTRY_ADDR_UPPER(r10) + +	/* setup branch addr */ +	mtspr	SPRN_SRR0,r4 + +	/* mark the entry as released */ +	li	r8,3 +	stw	r8,ENTRY_ADDR_LOWER(r10) + +	/* mask by ~64M to setup our tlb we will jump to */ +	rlwinm	r12,r4,0,0,5 + +	/* setup r3, r4, r5, r6, r7, r8, r9 */ +	lwz	r3,ENTRY_R3_LOWER(r10) +	li	r4,0 +	li	r5,0 +	lwz	r6,ENTRY_R6_LOWER(r10) +	lis	r7,(64*1024*1024)@h +	li	r8,0 +	li	r9,0 + +	/* load up the pir */ +	lwz	r0,ENTRY_PIR(r10) +	mtspr	SPRN_PIR,r0 +	mfspr	r0,SPRN_PIR +	stw	r0,ENTRY_PIR(r10) + +	mtspr	IVPR,r12 +/* + * Coming here, we know the cpu has one TLB mapping in TLB1[0] + * which maps 0xfffff000-0xffffffff one-to-one.  We set up a + * second mapping that maps addr 1:1 for 64M, and then we jump to + * addr + */ +	lis	r10,(MAS0_TLBSEL(1)|MAS0_ESEL(0))@h +	mtspr	SPRN_MAS0,r10 +	lis	r10,(MAS1_VALID|MAS1_IPROT)@h +	ori	r10,r10,(MAS1_TSIZE(BOOKE_PAGESZ_64M))@l +	mtspr	SPRN_MAS1,r10 +	/* WIMGE = 0b00000 for now */ +	mtspr	SPRN_MAS2,r12 +	ori	r12,r12,(MAS3_SX|MAS3_SW|MAS3_SR) +	mtspr	SPRN_MAS3,r12 +#ifdef CONFIG_ENABLE_36BIT_PHYS +	mtspr	SPRN_MAS7,r11 +#endif +	tlbwe + +/* Now we have another mapping for this page, so we jump to that + * mapping + */ +	mtspr	SPRN_SRR1,r13 +	rfi + +	/* +	 * Allocate some space for the SDRAM address of the bootpg. +	 * This variable has to be in the boot page so that it can +	 * be accessed by secondary cores when they come out of reset. +	 */ +	.globl __bootpg_addr +__bootpg_addr: +	.long	0 + +	.align L1_CACHE_SHIFT +	.globl __spin_table +__spin_table: +	.space CONFIG_MAX_CPUS*ENTRY_SIZE + +	/* Fill in the empty space.  The actual reset vector is +	 * the last word of the page */ +__secondary_start_code_end: +	.space 4092 - (__secondary_start_code_end - __secondary_start_page) +__secondary_reset_vector: +	b	__secondary_start_page diff --git a/arch/powerpc/cpu/mpc85xx/resetvec.S b/arch/powerpc/cpu/mpc85xx/resetvec.S new file mode 100644 index 000000000..29555d4a0 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/resetvec.S @@ -0,0 +1,2 @@ +	.section .resetvec,"ax" +	b _start_e500 diff --git a/arch/powerpc/cpu/mpc85xx/serial_scc.c b/arch/powerpc/cpu/mpc85xx/serial_scc.c new file mode 100644 index 000000000..2dab2124f --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/serial_scc.c @@ -0,0 +1,268 @@ +/* + * (C) Copyright 2003 Motorola Inc. + * Xianghua Xiao (X.Xiao@motorola.com) + * Modified based on 8260 for 8560. + * + * (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 + * + * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00. + */ + +/* + * Minimal serial functions needed to use one of the SCC ports + * as serial console interface. + */ + +#include <common.h> +#include <asm/cpm_85xx.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_CONS_ON_SCC) + +#if CONFIG_CONS_INDEX == 1	/* Console on SCC1 */ + +#define SCC_INDEX		0 +#define PROFF_SCC		PROFF_SCC1 +#define CMXSCR_MASK		(CMXSCR_GR1|CMXSCR_SC1|\ +					CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK) +#define CMXSCR_VALUE		(CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1) +#define CPM_CR_SCC_PAGE		CPM_CR_SCC1_PAGE +#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC1_SBLOCK + +#elif CONFIG_CONS_INDEX == 2	/* Console on SCC2 */ + +#define SCC_INDEX		1 +#define PROFF_SCC		PROFF_SCC2 +#define CMXSCR_MASK		(CMXSCR_GR2|CMXSCR_SC2|\ +					CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK) +#define CMXSCR_VALUE		(CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2) +#define CPM_CR_SCC_PAGE		CPM_CR_SCC2_PAGE +#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC2_SBLOCK + +#elif CONFIG_CONS_INDEX == 3	/* Console on SCC3 */ + +#define SCC_INDEX		2 +#define PROFF_SCC		PROFF_SCC3 +#define CMXSCR_MASK		(CMXSCR_GR3|CMXSCR_SC3|\ +					CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK) +#define CMXSCR_VALUE		(CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3) +#define CPM_CR_SCC_PAGE		CPM_CR_SCC3_PAGE +#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC3_SBLOCK + +#elif CONFIG_CONS_INDEX == 4	/* Console on SCC4 */ + +#define SCC_INDEX		3 +#define PROFF_SCC		PROFF_SCC4 +#define CMXSCR_MASK		(CMXSCR_GR4|CMXSCR_SC4|\ +					CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK) +#define CMXSCR_VALUE		(CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4) +#define CPM_CR_SCC_PAGE		CPM_CR_SCC4_PAGE +#define CPM_CR_SCC_SBLOCK	CPM_CR_SCC4_SBLOCK + +#else + +#error "console not correctly defined" + +#endif + +int serial_init (void) +{ +	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; +	volatile ccsr_cpm_scc_t *sp; +	volatile scc_uart_t *up; +	volatile cbd_t *tbdf, *rbdf; +	volatile ccsr_cpm_cp_t *cp = &(cpm->im_cpm_cp); +	uint	dpaddr; + +	/* initialize pointers to SCC */ + +	sp = (ccsr_cpm_scc_t *) &(cpm->im_cpm_scc[SCC_INDEX]); +	up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]); + +	/* Disable transmitter/receiver. +	*/ +	sp->gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + +	/* put the SCC channel into NMSI (non multiplexd serial interface) +	 * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15). +	 */ +	cpm->im_cpm_mux.cmxscr = \ +		(cpm->im_cpm_mux.cmxscr&~CMXSCR_MASK)|CMXSCR_VALUE; + +	/* Set up the baud rate generator. +	*/ +	serial_setbrg (); + +	/* Allocate space for two buffer descriptors in the DP ram. +	 * damm: allocating space after the two buffers for rx/tx data +	 */ + +	dpaddr = m8560_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); + +	/* Set the physical address of the host memory buffers in +	 * the buffer descriptors. +	 */ +	rbdf = (cbd_t *)&(cpm->im_dprambase[dpaddr]); +	rbdf->cbd_bufaddr = (uint) (rbdf+2); +	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; +	tbdf = rbdf + 1; +	tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; +	tbdf->cbd_sc = BD_SC_WRAP; + +	/* Set up the uart parameters in the parameter ram. +	*/ +	up->scc_genscc.scc_rbase = dpaddr; +	up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t); +	up->scc_genscc.scc_rfcr = CPMFCR_EB; +	up->scc_genscc.scc_tfcr = CPMFCR_EB; +	up->scc_genscc.scc_mrblr = 1; +	up->scc_maxidl = 0; +	up->scc_brkcr = 1; +	up->scc_parec = 0; +	up->scc_frmec = 0; +	up->scc_nosec = 0; +	up->scc_brkec = 0; +	up->scc_uaddr1 = 0; +	up->scc_uaddr2 = 0; +	up->scc_toseq = 0; +	up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000; +	up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000; +	up->scc_rccm = 0xc0ff; + +	/* Mask all interrupts and remove anything pending. +	*/ +	sp->sccm = 0; +	sp->scce = 0xffff; + +	/* Set 8 bit FIFO, 16 bit oversampling and UART mode. +	*/ +	sp->gsmrh = SCC_GSMRH_RFW;	/* 8 bit FIFO */ +	sp->gsmrl = \ +		SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART; + +	/* Set CTS no flow control, 1 stop bit, 8 bit character length, +	 * normal async UART mode, no parity +	 */ +	sp->psmr = SCU_PSMR_CL; + +	/* execute the "Init Rx and Tx params" CP command. +	*/ + +	while (cp->cpcr & CPM_CR_FLG)  /* wait if cp is busy */ +	  ; + +	cp->cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK, +					0, CPM_CR_INIT_TRX) | CPM_CR_FLG; + +	while (cp->cpcr & CPM_CR_FLG)  /* wait if cp is busy */ +	  ; + +	/* Enable transmitter/receiver. +	*/ +	sp->gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT; + +	return (0); +} + +void +serial_setbrg (void) +{ +#if defined(CONFIG_CONS_USE_EXTC) +	m8560_cpm_extcbrg(SCC_INDEX, gd->baudrate, +		CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL); +#else +	m8560_cpm_setbrg(SCC_INDEX, gd->baudrate); +#endif +} + +void +serial_putc(const char c) +{ +	volatile scc_uart_t	*up; +	volatile cbd_t		*tbdf; +	volatile ccsr_cpm_t	*cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; + +	if (c == '\n') +		serial_putc ('\r'); + +	up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]); +	tbdf = (cbd_t *)&(cpm->im_dprambase[up->scc_genscc.scc_tbase]); + +	/* Wait for last character to go. +	 */ +	while (tbdf->cbd_sc & BD_SC_READY) +		; + +	/* Load the character into the transmit buffer. +	 */ +	*(volatile char *)tbdf->cbd_bufaddr = c; +	tbdf->cbd_datlen = 1; +	tbdf->cbd_sc |= BD_SC_READY; +} + +void +serial_puts (const char *s) +{ +	while (*s) { +		serial_putc (*s++); +	} +} + +int +serial_getc(void) +{ +	volatile cbd_t		*rbdf; +	volatile scc_uart_t	*up; +	volatile ccsr_cpm_t	*cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; +	unsigned char		c; + +	up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]); +	rbdf = (cbd_t *)&(cpm->im_dprambase[up->scc_genscc.scc_rbase]); + +	/* Wait for character to show up. +	 */ +	while (rbdf->cbd_sc & BD_SC_EMPTY) +		; + +	/* Grab the char and clear the buffer again. +	 */ +	c = *(volatile unsigned char *)rbdf->cbd_bufaddr; +	rbdf->cbd_sc |= BD_SC_EMPTY; + +	return (c); +} + +int +serial_tstc() +{ +	volatile cbd_t		*rbdf; +	volatile scc_uart_t	*up; +	volatile ccsr_cpm_t	*cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; + +	up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]); +	rbdf = (cbd_t *)&(cpm->im_dprambase[up->scc_genscc.scc_rbase]); + +	return ((rbdf->cbd_sc & BD_SC_EMPTY) == 0); +} + +#endif	/* CONFIG_CONS_ON_SCC */ diff --git a/arch/powerpc/cpu/mpc85xx/speed.c b/arch/powerpc/cpu/mpc85xx/speed.c new file mode 100644 index 000000000..268edbc5b --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/speed.c @@ -0,0 +1,283 @@ +/* + * Copyright 2004, 2007-2009 Freescale Semiconductor, Inc. + * + * (C) Copyright 2003 Motorola Inc. + * Xianghua Xiao, (X.Xiao@motorola.com) + * + * (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 + */ + +#include <common.h> +#include <ppc_asm.tmpl> +#include <asm/processor.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* --------------------------------------------------------------- */ + +void get_sys_info (sys_info_t * sysInfo) +{ +	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +#ifdef CONFIG_FSL_CORENET +	volatile ccsr_clk_t *clk = (void *)(CONFIG_SYS_FSL_CORENET_CLK_ADDR); + +	const u8 core_cplx_PLL[16] = { +		[ 0] = 0,	/* CC1 PPL / 1 */ +		[ 1] = 0,	/* CC1 PPL / 2 */ +		[ 2] = 0,	/* CC1 PPL / 4 */ +		[ 4] = 1,	/* CC2 PPL / 1 */ +		[ 5] = 1,	/* CC2 PPL / 2 */ +		[ 6] = 1,	/* CC2 PPL / 4 */ +		[ 8] = 2,	/* CC3 PPL / 1 */ +		[ 9] = 2,	/* CC3 PPL / 2 */ +		[10] = 2,	/* CC3 PPL / 4 */ +		[12] = 3,	/* CC4 PPL / 1 */ +		[13] = 3,	/* CC4 PPL / 2 */ +		[14] = 3,	/* CC4 PPL / 4 */ +	}; + +	const u8 core_cplx_PLL_div[16] = { +		[ 0] = 1,	/* CC1 PPL / 1 */ +		[ 1] = 2,	/* CC1 PPL / 2 */ +		[ 2] = 4,	/* CC1 PPL / 4 */ +		[ 4] = 1,	/* CC2 PPL / 1 */ +		[ 5] = 2,	/* CC2 PPL / 2 */ +		[ 6] = 4,	/* CC2 PPL / 4 */ +		[ 8] = 1,	/* CC3 PPL / 1 */ +		[ 9] = 2,	/* CC3 PPL / 2 */ +		[10] = 4,	/* CC3 PPL / 4 */ +		[12] = 1,	/* CC4 PPL / 1 */ +		[13] = 2,	/* CC4 PPL / 2 */ +		[14] = 4,	/* CC4 PPL / 4 */ +	}; +	uint lcrr_div, i, freqCC_PLL[4], rcw_tmp; +	unsigned long sysclk = CONFIG_SYS_CLK_FREQ; + +	sysInfo->freqSystemBus = sysclk; +	sysInfo->freqDDRBus = sysclk; +	freqCC_PLL[0] = sysclk; +	freqCC_PLL[1] = sysclk; +	freqCC_PLL[2] = sysclk; +	freqCC_PLL[3] = sysclk; + +	sysInfo->freqSystemBus *= (in_be32(&gur->rcwsr[0]) >> 25) & 0x1f; +	sysInfo->freqDDRBus *= ((in_be32(&gur->rcwsr[0]) >> 17) & 0x1f); +	freqCC_PLL[0] *= (in_be32(&clk->pllc1gsr) >> 1) & 0x3f; +	freqCC_PLL[1] *= (in_be32(&clk->pllc2gsr) >> 1) & 0x3f; +	freqCC_PLL[2] *= (in_be32(&clk->pllc3gsr) >> 1) & 0x3f; +	freqCC_PLL[3] *= (in_be32(&clk->pllc4gsr) >> 1) & 0x3f; + +	rcw_tmp = in_be32(&gur->rcwsr[3]); +	for (i = 0; i < cpu_numcores(); i++) { +		u32 c_pll_sel = (in_be32(&clk->clkc0csr + i*8) >> 27) & 0xf; +		u32 cplx_pll = core_cplx_PLL[c_pll_sel]; + +		sysInfo->freqProcessor[i] = +			 freqCC_PLL[cplx_pll] / core_cplx_PLL_div[c_pll_sel]; +	} + +#define PME_CLK_SEL	0x80000000 +#define FM1_CLK_SEL	0x40000000 +#define FM2_CLK_SEL	0x20000000 +	rcw_tmp = in_be32(&gur->rcwsr[7]); + +#ifdef CONFIG_SYS_DPAA_PME +	if (rcw_tmp & PME_CLK_SEL) +		sysInfo->freqPME = freqCC_PLL[2] / 2; +	else +		sysInfo->freqPME = sysInfo->freqSystemBus / 2; +#endif + +#ifdef CONFIG_SYS_DPAA_FMAN +	if (rcw_tmp & FM1_CLK_SEL) +		sysInfo->freqFMan[0] = freqCC_PLL[2] / 2; +	else +		sysInfo->freqFMan[0] = sysInfo->freqSystemBus / 2; +#if (CONFIG_SYS_NUM_FMAN) == 2 +	if (rcw_tmp & FM2_CLK_SEL) +		sysInfo->freqFMan[1] = freqCC_PLL[2] / 2; +	else +		sysInfo->freqFMan[1] = sysInfo->freqSystemBus / 2; +#endif +#endif + +#else +	uint plat_ratio,e500_ratio,half_freqSystemBus; +	uint lcrr_div; +	int i; +#ifdef CONFIG_QE +	u32 qe_ratio; +#endif + +	plat_ratio = (gur->porpllsr) & 0x0000003e; +	plat_ratio >>= 1; +	sysInfo->freqSystemBus = plat_ratio * CONFIG_SYS_CLK_FREQ; + +	/* Divide before multiply to avoid integer +	 * overflow for processor speeds above 2GHz */ +	half_freqSystemBus = sysInfo->freqSystemBus/2; +	for (i = 0; i < cpu_numcores(); i++) { +		e500_ratio = ((gur->porpllsr) >> (i * 8 + 16)) & 0x3f; +		sysInfo->freqProcessor[i] = e500_ratio * half_freqSystemBus; +	} + +	/* Note: freqDDRBus is the MCLK frequency, not the data rate. */ +	sysInfo->freqDDRBus = sysInfo->freqSystemBus; + +#ifdef CONFIG_DDR_CLK_FREQ +	{ +		u32 ddr_ratio = ((gur->porpllsr) & MPC85xx_PORPLLSR_DDR_RATIO) +			>> MPC85xx_PORPLLSR_DDR_RATIO_SHIFT; +		if (ddr_ratio != 0x7) +			sysInfo->freqDDRBus = ddr_ratio * CONFIG_DDR_CLK_FREQ; +	} +#endif +#endif + +#ifdef CONFIG_QE +	qe_ratio = ((gur->porpllsr) & MPC85xx_PORPLLSR_QE_RATIO) +			>> MPC85xx_PORPLLSR_QE_RATIO_SHIFT; +	sysInfo->freqQE = qe_ratio * CONFIG_SYS_CLK_FREQ; +#endif + +#if defined(CONFIG_SYS_LBC_LCRR) +	/* We will program LCRR to this value later */ +	lcrr_div = CONFIG_SYS_LBC_LCRR & LCRR_CLKDIV; +#else +	{ +	    volatile ccsr_lbc_t *lbc = (void *)(CONFIG_SYS_MPC85xx_LBC_ADDR); +	    lcrr_div = in_be32(&lbc->lcrr) & LCRR_CLKDIV; +	} +#endif +	if (lcrr_div == 2 || lcrr_div == 4 || lcrr_div == 8) { +#if defined(CONFIG_FSL_CORENET) +		/* If this is corenet based SoC, bit-representation +		 * for four times the clock divider values. +		 */ +		lcrr_div *= 4; +#elif !defined(CONFIG_MPC8540) && !defined(CONFIG_MPC8541) && \ +    !defined(CONFIG_MPC8555) && !defined(CONFIG_MPC8560) +		/* +		 * Yes, the entire PQ38 family use the same +		 * bit-representation for twice the clock divider values. +		 */ +		lcrr_div *= 2; +#endif +		sysInfo->freqLocalBus = sysInfo->freqSystemBus / lcrr_div; +	} else { +		/* In case anyone cares what the unknown value is */ +		sysInfo->freqLocalBus = lcrr_div; +	} +} + + +int get_clocks (void) +{ +	sys_info_t sys_info; +#ifdef CONFIG_MPC8544 +	volatile ccsr_gur_t *gur = (void *) CONFIG_SYS_MPC85xx_GUTS_ADDR; +#endif +#if defined(CONFIG_CPM2) +	volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR; +	uint sccr, dfbrg; + +	/* set VCO = 4 * BRG */ +	cpm->im_cpm_intctl.sccr &= 0xfffffffc; +	sccr = cpm->im_cpm_intctl.sccr; +	dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT; +#endif +	get_sys_info (&sys_info); +	gd->cpu_clk = sys_info.freqProcessor[0]; +	gd->bus_clk = sys_info.freqSystemBus; +	gd->mem_clk = sys_info.freqDDRBus; +	gd->lbc_clk = sys_info.freqLocalBus; + +#ifdef CONFIG_QE +	gd->qe_clk = sys_info.freqQE; +	gd->brg_clk = gd->qe_clk / 2; +#endif +	/* +	 * The base clock for I2C depends on the actual SOC.  Unfortunately, +	 * there is no pattern that can be used to determine the frequency, so +	 * the only choice is to look up the actual SOC number and use the value +	 * for that SOC. This information is taken from application note +	 * AN2919. +	 */ +#if defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ +	defined(CONFIG_MPC8560) || defined(CONFIG_MPC8555) +	gd->i2c1_clk = sys_info.freqSystemBus; +#elif defined(CONFIG_MPC8544) +	/* +	 * On the 8544, the I2C clock is the same as the SEC clock.  This can be +	 * either CCB/2 or CCB/3, depending on the value of cfg_sec_freq. See +	 * 4.4.3.3 of the 8544 RM.  Note that this might actually work for all +	 * 85xx, but only the 8544 has cfg_sec_freq, so it's unknown if the +	 * PORDEVSR2_SEC_CFG bit is 0 on all 85xx boards that are not an 8544. +	 */ +	if (gur->pordevsr2 & MPC85xx_PORDEVSR2_SEC_CFG) +		gd->i2c1_clk = sys_info.freqSystemBus / 3; +	else +		gd->i2c1_clk = sys_info.freqSystemBus / 2; +#else +	/* Most 85xx SOCs use CCB/2, so this is the default behavior. */ +	gd->i2c1_clk = sys_info.freqSystemBus / 2; +#endif +	gd->i2c2_clk = gd->i2c1_clk; + +#if defined(CONFIG_FSL_ESDHC) +#ifdef CONFIG_MPC8569 +	gd->sdhc_clk = gd->bus_clk; +#else +	gd->sdhc_clk = gd->bus_clk / 2; +#endif +#endif /* defined(CONFIG_FSL_ESDHC) */ + +#if defined(CONFIG_CPM2) +	gd->vco_out = 2*sys_info.freqSystemBus; +	gd->cpm_clk = gd->vco_out / 2; +	gd->scc_clk = gd->vco_out / 4; +	gd->brg_clk = gd->vco_out / (1 << (2 * (dfbrg + 1))); +#endif + +	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) +{ +	return gd->bus_clk; +} + +/******************************************** + * get_ddr_freq + * return ddr bus freq in Hz + *********************************************/ +ulong get_ddr_freq (ulong dummy) +{ +	return gd->mem_clk; +} diff --git a/arch/powerpc/cpu/mpc85xx/start.S b/arch/powerpc/cpu/mpc85xx/start.S new file mode 100644 index 000000000..b3cb56a5b --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/start.S @@ -0,0 +1,1195 @@ +/* + * Copyright 2004, 2007-2010 Freescale Semiconductor, Inc. + * Copyright (C) 2003  Motorola,Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* U-Boot Startup Code for Motorola 85xx PowerPC based Embedded Boards + * + * The processor starts at 0xfffffffc and the code is first executed in the + * last 4K page(0xfffff000-0xffffffff) in flash/rom. + * + */ + +#include <config.h> +#include <mpc85xx.h> +#include <timestamp.h> +#include <version.h> + +#define _LINUX_CONFIG_H 1	/* avoid reading Linux autoconf.h file	*/ + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +#include <asm/cache.h> +#include <asm/mmu.h> + +#ifndef	 CONFIG_IDENT_STRING +#define	 CONFIG_IDENT_STRING "" +#endif + +#undef	MSR_KERNEL +#define MSR_KERNEL ( MSR_ME )	/* Machine Check */ + +/* + * Set up GOT: Global Offset Table + * + * Use r12 to access the GOT + */ +	START_GOT +	GOT_ENTRY(_GOT2_TABLE_) +	GOT_ENTRY(_FIXUP_TABLE_) + +#ifndef CONFIG_NAND_SPL +	GOT_ENTRY(_start) +	GOT_ENTRY(_start_of_vectors) +	GOT_ENTRY(_end_of_vectors) +	GOT_ENTRY(transfer_to_handler) +#endif + +	GOT_ENTRY(__init_end) +	GOT_ENTRY(_end) +	GOT_ENTRY(__bss_start) +	END_GOT + +/* + * e500 Startup -- after reset only the last 4KB of the effective + * address space is mapped in the MMU L2 TLB1 Entry0. The .bootpg + * section is located at THIS LAST page and basically does three + * things: clear some registers, set up exception tables and + * add more TLB entries for 'larger spaces'(e.g. the boot rom) to + * continue the boot procedure. + + * Once the boot rom is mapped by TLB entries we can proceed + * with normal startup. + * + */ + +	.section .bootpg,"ax" +	.globl _start_e500 + +_start_e500: + +/* clear registers/arrays not reset by hardware */ + +	/* L1 */ +	li	r0,2 +	mtspr	L1CSR0,r0	/* invalidate d-cache */ +	mtspr	L1CSR1,r0	/* invalidate i-cache */ + +	mfspr	r1,DBSR +	mtspr	DBSR,r1		/* Clear all valid bits */ + +	/* +	 *	Enable L1 Caches early +	 * +	 */ + +#if defined(CONFIG_E500MC) && defined(CONFIG_SYS_CACHE_STASHING) +	/* set stash id to (coreID) * 2 + 32 + L1 CT (0) */ +	li	r2,(32 + 0) +	mtspr	L1CSR2,r2 +#endif + +	/* Enable/invalidate the I-Cache */ +	lis	r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@h +	ori	r2,r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@l +	mtspr	SPRN_L1CSR1,r2 +1: +	mfspr	r3,SPRN_L1CSR1 +	and.	r1,r3,r2 +	bne	1b + +	lis	r3,(L1CSR1_CPE|L1CSR1_ICE)@h +	ori	r3,r3,(L1CSR1_CPE|L1CSR1_ICE)@l +	mtspr	SPRN_L1CSR1,r3 +	isync +2: +	mfspr	r3,SPRN_L1CSR1 +	andi.	r1,r3,L1CSR1_ICE@l +	beq	2b + +	/* Enable/invalidate the D-Cache */ +	lis	r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@h +	ori	r2,r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@l +	mtspr	SPRN_L1CSR0,r2 +1: +	mfspr	r3,SPRN_L1CSR0 +	and.	r1,r3,r2 +	bne	1b + +	lis	r3,(L1CSR0_CPE|L1CSR0_DCE)@h +	ori	r3,r3,(L1CSR0_CPE|L1CSR0_DCE)@l +	mtspr	SPRN_L1CSR0,r3 +	isync +2: +	mfspr	r3,SPRN_L1CSR0 +	andi.	r1,r3,L1CSR0_DCE@l +	beq	2b + +	/* Setup interrupt vectors */ +	lis	r1,TEXT_BASE@h +	mtspr	IVPR,r1 + +	li	r1,0x0100 +	mtspr	IVOR0,r1	/* 0: Critical input */ +	li	r1,0x0200 +	mtspr	IVOR1,r1	/* 1: Machine check */ +	li	r1,0x0300 +	mtspr	IVOR2,r1	/* 2: Data storage */ +	li	r1,0x0400 +	mtspr	IVOR3,r1	/* 3: Instruction storage */ +	li	r1,0x0500 +	mtspr	IVOR4,r1	/* 4: External interrupt */ +	li	r1,0x0600 +	mtspr	IVOR5,r1	/* 5: Alignment */ +	li	r1,0x0700 +	mtspr	IVOR6,r1	/* 6: Program check */ +	li	r1,0x0800 +	mtspr	IVOR7,r1	/* 7: floating point unavailable */ +	li	r1,0x0900 +	mtspr	IVOR8,r1	/* 8: System call */ +	/* 9: Auxiliary processor unavailable(unsupported) */ +	li	r1,0x0a00 +	mtspr	IVOR10,r1	/* 10: Decrementer */ +	li	r1,0x0b00 +	mtspr	IVOR11,r1	/* 11: Interval timer */ +	li	r1,0x0c00 +	mtspr	IVOR12,r1	/* 12: Watchdog timer */ +	li	r1,0x0d00 +	mtspr	IVOR13,r1	/* 13: Data TLB error */ +	li	r1,0x0e00 +	mtspr	IVOR14,r1	/* 14: Instruction TLB error */ +	li	r1,0x0f00 +	mtspr	IVOR15,r1	/* 15: Debug */ + +	/* Clear and set up some registers. */ +	li      r0,0x0000 +	lis	r1,0xffff +	mtspr	DEC,r0			/* prevent dec exceptions */ +	mttbl	r0			/* prevent fit & wdt exceptions */ +	mttbu	r0 +	mtspr	TSR,r1			/* clear all timer exception status */ +	mtspr	TCR,r0			/* disable all */ +	mtspr	ESR,r0			/* clear exception syndrome register */ +	mtspr	MCSR,r0			/* machine check syndrome register */ +	mtxer	r0			/* clear integer exception register */ + +#ifdef CONFIG_SYS_BOOK3E_HV +	mtspr	MAS8,r0			/* make sure MAS8 is clear */ +#endif + +	/* Enable Time Base and Select Time Base Clock */ +	lis	r0,HID0_EMCP@h		/* Enable machine check */ +#if defined(CONFIG_ENABLE_36BIT_PHYS) +	ori	r0,r0,HID0_ENMAS7@l	/* Enable MAS7 */ +#endif +#ifndef CONFIG_E500MC +	ori	r0,r0,HID0_TBEN@l	/* Enable Timebase */ +#endif +	mtspr	HID0,r0 + +#ifndef CONFIG_E500MC +	li	r0,(HID1_ASTME|HID1_ABE)@l	/* Addr streaming & broadcast */ +	mfspr	r3,PVR +	andi.	r3,r3, 0xff +	cmpwi	r3,0x50@l	/* if we are rev 5.0 or greater set MBDD */ +	blt 1f +	/* Set MBDD bit also */ +	ori r0, r0, HID1_MBDD@l +1: +	mtspr	HID1,r0 +#endif + +	/* Enable Branch Prediction */ +#if defined(CONFIG_BTB) +	lis	r0,BUCSR_ENABLE@h +	ori	r0,r0,BUCSR_ENABLE@l +	mtspr	SPRN_BUCSR,r0 +#endif + +#if defined(CONFIG_SYS_INIT_DBCR) +	lis	r1,0xffff +	ori	r1,r1,0xffff +	mtspr	DBSR,r1			/* Clear all status bits */ +	lis	r0,CONFIG_SYS_INIT_DBCR@h	/* DBCR0[IDM] must be set */ +	ori	r0,r0,CONFIG_SYS_INIT_DBCR@l +	mtspr	DBCR0,r0 +#endif + +#ifdef CONFIG_MPC8569 +#define CONFIG_SYS_LBC_ADDR (CONFIG_SYS_CCSRBAR_DEFAULT + 0x5000) +#define CONFIG_SYS_LBCR_ADDR (CONFIG_SYS_LBC_ADDR + 0xd0) + +	/* MPC8569 Rev.0 silcon needs to set bit 13 of LBCR to allow elBC to +	 * use address space which is more than 12bits, and it must be done in +	 * the 4K boot page. So we set this bit here. +	 */ + +	/* create a temp mapping TLB0[0] for LBCR  */ +	lis     r6,FSL_BOOKE_MAS0(0, 0, 0)@h +	ori     r6,r6,FSL_BOOKE_MAS0(0, 0, 0)@l + +	lis     r7,FSL_BOOKE_MAS1(1, 0, 0, 0, BOOKE_PAGESZ_4K)@h +	ori     r7,r7,FSL_BOOKE_MAS1(1, 0, 0, 0, BOOKE_PAGESZ_4K)@l + +	lis     r8,FSL_BOOKE_MAS2(CONFIG_SYS_LBC_ADDR, MAS2_I|MAS2_G)@h +	ori     r8,r8,FSL_BOOKE_MAS2(CONFIG_SYS_LBC_ADDR, MAS2_I|MAS2_G)@l + +	lis     r9,FSL_BOOKE_MAS3(CONFIG_SYS_LBC_ADDR, 0, +						(MAS3_SX|MAS3_SW|MAS3_SR))@h +	ori     r9,r9,FSL_BOOKE_MAS3(CONFIG_SYS_LBC_ADDR, 0, +						(MAS3_SX|MAS3_SW|MAS3_SR))@l + +	mtspr   MAS0,r6 +	mtspr   MAS1,r7 +	mtspr   MAS2,r8 +	mtspr   MAS3,r9 +	isync +	msync +	tlbwe + +	/* Set LBCR register */ +	lis     r4,CONFIG_SYS_LBCR_ADDR@h +	ori     r4,r4,CONFIG_SYS_LBCR_ADDR@l + +	lis     r5,CONFIG_SYS_LBC_LBCR@h +	ori     r5,r5,CONFIG_SYS_LBC_LBCR@l +	stw     r5,0(r4) +	isync + +	/* invalidate this temp TLB */ +	lis	r4,CONFIG_SYS_LBC_ADDR@h +	ori	r4,r4,CONFIG_SYS_LBC_ADDR@l +	tlbivax	0,r4 +	isync + +#endif /* CONFIG_MPC8569 */ + +	lis     r6,FSL_BOOKE_MAS0(1, 15, 0)@h +	ori     r6,r6,FSL_BOOKE_MAS0(1, 15, 0)@l + +#ifndef CONFIG_SYS_RAMBOOT +	/* create a temp mapping in AS=1 to the 4M boot window */ +	lis     r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_4M)@h +	ori     r7,r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_4M)@l + +	lis     r8,FSL_BOOKE_MAS2(TEXT_BASE & 0xffc00000, (MAS2_I|MAS2_G))@h +	ori     r8,r8,FSL_BOOKE_MAS2(TEXT_BASE & 0xffc00000, (MAS2_I|MAS2_G))@l + +	/* The 85xx has the default boot window 0xff800000 - 0xffffffff */ +	lis     r9,FSL_BOOKE_MAS3(0xffc00000, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@h +	ori     r9,r9,FSL_BOOKE_MAS3(0xffc00000, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@l +#else +	/* +	 * create a temp mapping in AS=1 to the 1M TEXT_BASE space, the main +	 * image has been relocated to TEXT_BASE on the second stage. +	 */ +	lis     r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_1M)@h +	ori     r7,r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_1M)@l + +	lis     r8,FSL_BOOKE_MAS2(TEXT_BASE, (MAS2_I|MAS2_G))@h +	ori     r8,r8,FSL_BOOKE_MAS2(TEXT_BASE, (MAS2_I|MAS2_G))@l + +	lis     r9,FSL_BOOKE_MAS3(TEXT_BASE, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@h +	ori     r9,r9,FSL_BOOKE_MAS3(TEXT_BASE, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@l +#endif + +	mtspr   MAS0,r6 +	mtspr   MAS1,r7 +	mtspr   MAS2,r8 +	mtspr   MAS3,r9 +	isync +	msync +	tlbwe + +	/* create a temp mapping in AS=1 to the stack */ +	lis     r6,FSL_BOOKE_MAS0(1, 14, 0)@h +	ori     r6,r6,FSL_BOOKE_MAS0(1, 14, 0)@l + +	lis     r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_16K)@h +	ori     r7,r7,FSL_BOOKE_MAS1(1, 1, 0, 1, BOOKE_PAGESZ_16K)@l + +	lis     r8,FSL_BOOKE_MAS2(CONFIG_SYS_INIT_RAM_ADDR, 0)@h +	ori     r8,r8,FSL_BOOKE_MAS2(CONFIG_SYS_INIT_RAM_ADDR, 0)@l + +	lis     r9,FSL_BOOKE_MAS3(CONFIG_SYS_INIT_RAM_ADDR, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@h +	ori     r9,r9,FSL_BOOKE_MAS3(CONFIG_SYS_INIT_RAM_ADDR, 0, (MAS3_SX|MAS3_SW|MAS3_SR))@l + +	mtspr   MAS0,r6 +	mtspr   MAS1,r7 +	mtspr   MAS2,r8 +	mtspr   MAS3,r9 +	isync +	msync +	tlbwe + +	lis	r6,MSR_IS|MSR_DS@h +	ori	r6,r6,MSR_IS|MSR_DS@l +	lis	r7,switch_as@h +	ori	r7,r7,switch_as@l + +	mtspr	SPRN_SRR0,r7 +	mtspr	SPRN_SRR1,r6 +	rfi + +switch_as: +/* L1 DCache is used for initial RAM */ + +	/* Allocate Initial RAM in data cache. +	 */ +	lis	r3,CONFIG_SYS_INIT_RAM_ADDR@h +	ori	r3,r3,CONFIG_SYS_INIT_RAM_ADDR@l +	mfspr	r2, L1CFG0 +	andi.	r2, r2, 0x1ff +	/* cache size * 1024 / (2 * L1 line size) */ +	slwi	r2, r2, (10 - 1 - L1_CACHE_SHIFT) +	mtctr	r2 +	li	r0,0 +1: +	dcbz	r0,r3 +	dcbtls	0,r0,r3 +	addi	r3,r3,CONFIG_SYS_CACHELINE_SIZE +	bdnz	1b + +	/* Jump out the last 4K page and continue to 'normal' start */ +#ifdef CONFIG_SYS_RAMBOOT +	b	_start_cont +#else +	/* Calculate absolute address in FLASH and jump there		*/ +	/*--------------------------------------------------------------*/ +	lis	r3,CONFIG_SYS_MONITOR_BASE@h +	ori	r3,r3,CONFIG_SYS_MONITOR_BASE@l +	addi	r3,r3,_start_cont - _start + _START_OFFSET +	mtlr	r3 +	blr +#endif + +	.text +	.globl	_start +_start: +	.long	0x27051956		/* U-BOOT Magic Number */ +	.globl	version_string +version_string: +	.ascii U_BOOT_VERSION +	.ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")" +	.ascii CONFIG_IDENT_STRING, "\0" + +	.align	4 +	.globl	_start_cont +_start_cont: +	/* Setup the stack in initial RAM,could be L2-as-SRAM or L1 dcache*/ +	lis	r1,CONFIG_SYS_INIT_RAM_ADDR@h +	ori	r1,r1,CONFIG_SYS_INIT_SP_OFFSET@l + +	li	r0,0 +	stwu	r0,-4(r1) +	stwu	r0,-4(r1)		/* Terminate call chain */ + +	stwu	r1,-8(r1)		/* Save back chain and move SP */ +	lis	r0,RESET_VECTOR@h	/* Address of reset vector */ +	ori	r0,r0,RESET_VECTOR@l +	stwu	r1,-8(r1)		/* Save back chain and move SP */ +	stw	r0,+12(r1)		/* Save return addr (underflow vect) */ + +	GET_GOT +	bl	cpu_init_early_f + +	/* switch back to AS = 0 */ +	lis	r3,(MSR_CE|MSR_ME|MSR_DE)@h +	ori	r3,r3,(MSR_CE|MSR_ME|MSR_DE)@l +	mtmsr	r3 +	isync + +	bl	cpu_init_f +	bl	board_init_f +	isync + +#ifndef CONFIG_NAND_SPL +	. = EXC_OFF_SYS_RESET +	.globl	_start_of_vectors +_start_of_vectors: + +/* Critical input. */ +	CRIT_EXCEPTION(0x0100, CriticalInput, CritcalInputException) + +/* Machine check */ +	MCK_EXCEPTION(0x200, MachineCheck, MachineCheckException) + +/* Data Storage exception. */ +	STD_EXCEPTION(0x0300, DataStorage, UnknownException) + +/* Instruction Storage exception. */ +	STD_EXCEPTION(0x0400, InstStorage, UnknownException) + +/* External Interrupt exception. */ +	STD_EXCEPTION(0x0500, ExtInterrupt, ExtIntException) + +/* Alignment exception. */ +	. = 0x0600 +Alignment: +	EXCEPTION_PROLOG(SRR0, SRR1) +	mfspr	r4,DAR +	stw	r4,_DAR(r21) +	mfspr	r5,DSISR +	stw	r5,_DSISR(r21) +	addi	r3,r1,STACK_FRAME_OVERHEAD +	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE) + +/* Program check exception */ +	. = 0x0700 +ProgramCheck: +	EXCEPTION_PROLOG(SRR0, SRR1) +	addi	r3,r1,STACK_FRAME_OVERHEAD +	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException, +		MSR_KERNEL, COPY_EE) + +	/* No FPU on MPC85xx.  This exception is not supposed to happen. +	*/ +	STD_EXCEPTION(0x0800, FPUnavailable, UnknownException) + +	. = 0x0900 +/* + * r0 - SYSCALL number + * r3-... arguments + */ +SystemCall: +	addis	r11,r0,0	/* get functions table addr */ +	ori	r11,r11,0	/* Note: this code is patched in trap_init */ +	addis	r12,r0,0	/* get number of functions */ +	ori	r12,r12,0 + +	cmplw	0,r0,r12 +	bge	1f + +	rlwinm	r0,r0,2,0,31	/* fn_addr = fn_tbl[r0] */ +	add	r11,r11,r0 +	lwz	r11,0(r11) + +	li	r20,0xd00-4	/* Get stack pointer */ +	lwz	r12,0(r20) +	subi	r12,r12,12	/* Adjust stack pointer */ +	li	r0,0xc00+_end_back-SystemCall +	cmplw	0,r0,r12	/* Check stack overflow */ +	bgt	1f +	stw	r12,0(r20) + +	mflr	r0 +	stw	r0,0(r12) +	mfspr	r0,SRR0 +	stw	r0,4(r12) +	mfspr	r0,SRR1 +	stw	r0,8(r12) + +	li	r12,0xc00+_back-SystemCall +	mtlr	r12 +	mtspr	SRR0,r11 + +1:	SYNC +	rfi +_back: + +	mfmsr	r11			/* Disable interrupts */ +	li	r12,0 +	ori	r12,r12,MSR_EE +	andc	r11,r11,r12 +	SYNC				/* Some chip revs need this... */ +	mtmsr	r11 +	SYNC + +	li	r12,0xd00-4		/* restore regs */ +	lwz	r12,0(r12) + +	lwz	r11,0(r12) +	mtlr	r11 +	lwz	r11,4(r12) +	mtspr	SRR0,r11 +	lwz	r11,8(r12) +	mtspr	SRR1,r11 + +	addi	r12,r12,12		/* Adjust stack pointer */ +	li	r20,0xd00-4 +	stw	r12,0(r20) + +	SYNC +	rfi +_end_back: + +	STD_EXCEPTION(0x0a00, Decrementer, timer_interrupt) +	STD_EXCEPTION(0x0b00, IntervalTimer, UnknownException) +	STD_EXCEPTION(0x0c00, WatchdogTimer, UnknownException) + +	STD_EXCEPTION(0x0d00, DataTLBError, UnknownException) +	STD_EXCEPTION(0x0e00, InstructionTLBError, UnknownException) + +	CRIT_EXCEPTION(0x0f00, DebugBreakpoint, DebugException ) + +	.globl	_end_of_vectors +_end_of_vectors: + + +	. = . + (0x100 - ( . & 0xff ))	/* align for debug */ + +/* + * 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 + +crit_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	SPRN_CSRR0,r2 +	mtspr	SPRN_CSRR1,r0 +	lwz	r0,GPR0(r1) +	lwz	r2,GPR2(r1) +	lwz	r1,GPR1(r1) +	SYNC +	rfci + +mck_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	SPRN_MCSRR0,r2 +	mtspr	SPRN_MCSRR1,r0 +	lwz	r0,GPR0(r1) +	lwz	r2,GPR2(r1) +	lwz	r1,GPR1(r1) +	SYNC +	rfmci + +/* Cache functions. +*/ +.globl invalidate_icache +invalidate_icache: +	mfspr	r0,L1CSR1 +	ori	r0,r0,L1CSR1_ICFI +	msync +	isync +	mtspr	L1CSR1,r0 +	isync +	blr				/* entire I cache */ + +.globl invalidate_dcache +invalidate_dcache: +	mfspr	r0,L1CSR0 +	ori	r0,r0,L1CSR0_DCFI +	msync +	isync +	mtspr	L1CSR0,r0 +	isync +	blr + +	.globl	icache_enable +icache_enable: +	mflr	r8 +	bl	invalidate_icache +	mtlr	r8 +	isync +	mfspr	r4,L1CSR1 +	ori	r4,r4,0x0001 +	oris	r4,r4,0x0001 +	mtspr	L1CSR1,r4 +	isync +	blr + +	.globl	icache_disable +icache_disable: +	mfspr	r0,L1CSR1 +	lis	r3,0 +	ori	r3,r3,L1CSR1_ICE +	andc	r0,r0,r3 +	mtspr	L1CSR1,r0 +	isync +	blr + +	.globl	icache_status +icache_status: +	mfspr	r3,L1CSR1 +	andi.	r3,r3,L1CSR1_ICE +	blr + +	.globl	dcache_enable +dcache_enable: +	mflr	r8 +	bl	invalidate_dcache +	mtlr	r8 +	isync +	mfspr	r0,L1CSR0 +	ori	r0,r0,0x0001 +	oris	r0,r0,0x0001 +	msync +	isync +	mtspr	L1CSR0,r0 +	isync +	blr + +	.globl	dcache_disable +dcache_disable: +	mfspr	r3,L1CSR0 +	lis	r4,0 +	ori	r4,r4,L1CSR0_DCE +	andc	r3,r3,r4 +	mtspr	L1CSR0,r0 +	isync +	blr + +	.globl	dcache_status +dcache_status: +	mfspr	r3,L1CSR0 +	andi.	r3,r3,L1CSR0_DCE +	blr + +	.globl get_pir +get_pir: +	mfspr	r3,PIR +	blr + +	.globl get_pvr +get_pvr: +	mfspr	r3,PVR +	blr + +	.globl get_svr +get_svr: +	mfspr	r3,SVR +	blr + +	.globl wr_tcr +wr_tcr: +	mtspr	TCR,r3 +	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) +	sync +	blr + +/*------------------------------------------------------------------------------- */ +/* Function:	 out16 */ +/* Description:	 Output 16 bits */ +/*------------------------------------------------------------------------------- */ +	.globl	out16 +out16: +	sth	r4,0x0000(r3) +	sync +	blr + +/*------------------------------------------------------------------------------- */ +/* Function:	 out16r */ +/* Description:	 Byte reverse and output 16 bits */ +/*------------------------------------------------------------------------------- */ +	.globl	out16r +out16r: +	sthbrx	r4,r0,r3 +	sync +	blr + +/*------------------------------------------------------------------------------- */ +/* Function:	 out32 */ +/* Description:	 Output 32 bits */ +/*------------------------------------------------------------------------------- */ +	.globl	out32 +out32: +	stw	r4,0x0000(r3) +	sync +	blr + +/*------------------------------------------------------------------------------- */ +/* Function:	 out32r */ +/* Description:	 Byte reverse and output 32 bits */ +/*------------------------------------------------------------------------------- */ +	.globl	out32r +out32r: +	stwbrx	r4,r0,r3 +	sync +	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 +#endif  /* !CONFIG_NAND_SPL */ + +/*------------------------------------------------------------------------------*/ + +/* + * void write_tlb(mas0, mas1, mas2, mas3, mas7) + */ +	.globl	write_tlb +write_tlb: +	mtspr	MAS0,r3 +	mtspr	MAS1,r4 +	mtspr	MAS2,r5 +	mtspr	MAS3,r6 +#ifdef CONFIG_ENABLE_36BIT_PHYS +	mtspr	MAS7,r7 +#endif +	li	r3,0 +#ifdef CONFIG_SYS_BOOK3E_HV +	mtspr	MAS8,r3 +#endif +	isync +	tlbwe +	msync +	isync +	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 Init Data pointer	*/ +	mr	r10,r5		/* Save copy of Destination Address	*/ + +	GET_GOT +	mr	r3,r5				/* Destination Address	*/ +	lis	r4,CONFIG_SYS_MONITOR_BASE@h		/* Source      Address	*/ +	ori	r4,r4,CONFIG_SYS_MONITOR_BASE@l +	lwz	r5,GOT(__init_end) +	sub	r5,r5,r4 +	li	r6,CONFIG_SYS_CACHELINE_SIZE		/* Cache Line Size	*/ + +	/* +	 * Fix GOT pointer: +	 * +	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address +	 * +	 * Offset: +	 */ +	sub	r15,r10,r4 + +	/* First our own GOT */ +	add	r12,r12,r15 +	/* the the one used by the C code */ +	add	r30,r30,r15 + +	/* +	 * Now relocate code +	 */ + +	cmplw	cr1,r3,r4 +	addi	r0,r5,3 +	srwi.	r0,r0,2 +	beq	cr1,4f		/* In place copy is not necessary	*/ +	beq	7f		/* Protect against 0 count		*/ +	mtctr	r0 +	bge	cr1,2f + +	la	r8,-4(r4) +	la	r7,-4(r3) +1:	lwzu	r0,4(r8) +	stwu	r0,4(r7) +	bdnz	1b +	b	4f + +2:	slwi	r0,r0,2 +	add	r8,r4,r0 +	add	r7,r3,r0 +3:	lwzu	r0,-4(r8) +	stwu	r0,-4(r7) +	bdnz	3b + +/* + * Now flush the cache: note that we must start from a cache aligned + * address. Otherwise we might miss one cache line. + */ +4:	cmpwi	r6,0 +	add	r5,r3,r5 +	beq	7f		/* Always flush prefetch queue in any case */ +	subi	r0,r6,1 +	andc	r3,r3,r0 +	mr	r4,r3 +5:	dcbst	0,r4 +	add	r4,r4,r6 +	cmplw	r4,r5 +	blt	5b +	sync			/* Wait for all dcbst to complete on bus */ +	mr	r4,r3 +6:	icbi	0,r4 +	add	r4,r4,r6 +	cmplw	r4,r5 +	blt	6b +7:	sync			/* Wait for all icbi to complete on bus */ +	isync + +	/* +	 * Re-point the IVPR at RAM +	 */ +	mtspr	IVPR,r10 + +/* + * We are done. Do not return, instead branch to second part of board + * initialization, now running from RAM. + */ + +	addi	r0,r10,in_ram - _start + _START_OFFSET +	mtlr	r0 +	blr				/* NEVER RETURNS! */ +	.globl	in_ram +in_ram: + +	/* +	 * Relocation Function, r12 point to got2+0x8000 +	 * +	 * Adjust got2 pointers, no need to check for 0, this code +	 * already puts a few entries in the table. +	 */ +	li	r0,__got2_entries@sectoff@l +	la	r3,GOT(_GOT2_TABLE_) +	lwz	r11,GOT(_GOT2_TABLE_) +	mtctr	r0 +	sub	r11,r3,r11 +	addi	r3,r3,-4 +1:	lwzu	r0,4(r3) +	cmpwi	r0,0 +	beq-	2f +	add	r0,r0,r11 +	stw	r0,0(r3) +2:	bdnz	1b + +	/* +	 * Now adjust the fixups and the pointers to the fixups +	 * in case we need to move ourselves again. +	 */ +	li	r0,__fixup_entries@sectoff@l +	lwz	r3,GOT(_FIXUP_TABLE_) +	cmpwi	r0,0 +	mtctr	r0 +	addi	r3,r3,-4 +	beq	4f +3:	lwzu	r4,4(r3) +	lwzux	r0,r4,r11 +	add	r0,r0,r11 +	stw	r10,0(r3) +	stw	r0,0(r4) +	bdnz	3b +4: +clear_bss: +	/* +	 * Now clear BSS segment +	 */ +	lwz	r3,GOT(__bss_start) +	lwz	r4,GOT(_end) + +	cmplw	0,r3,r4 +	beq	6f + +	li	r0,0 +5: +	stw	r0,0(r3) +	addi	r3,r3,4 +	cmplw	0,r3,r4 +	bne	5b +6: + +	mr	r3,r9		/* Init Data pointer		*/ +	mr	r4,r10		/* Destination Address		*/ +	bl	board_init_r + +#ifndef CONFIG_NAND_SPL +	/* +	 * Copy exception vector code to low memory +	 * +	 * r3: dest_addr +	 * r7: source address, r8: end address, r9: target address +	 */ +	.globl	trap_init +trap_init: +	mflr	r4			/* save link register		*/ +	GET_GOT +	lwz	r7,GOT(_start_of_vectors) +	lwz	r8,GOT(_end_of_vectors) + +	li	r9,0x100		/* reset vector always at 0x100 */ + +	cmplw	0,r7,r8 +	bgelr				/* return if r7>=r8 - just in case */ +1: +	lwz	r0,0(r7) +	stw	r0,0(r9) +	addi	r7,r7,4 +	addi	r9,r9,4 +	cmplw	0,r7,r8 +	bne	1b + +	/* +	 * relocate `hdlr' and `int_return' entries +	 */ +	li	r7,.L_CriticalInput - _start + _START_OFFSET +	bl	trap_reloc +	li	r7,.L_MachineCheck - _start + _START_OFFSET +	bl	trap_reloc +	li	r7,.L_DataStorage - _start + _START_OFFSET +	bl	trap_reloc +	li	r7,.L_InstStorage - _start + _START_OFFSET +	bl	trap_reloc +	li	r7,.L_ExtInterrupt - _start + _START_OFFSET +	bl	trap_reloc +	li	r7,.L_Alignment - _start + _START_OFFSET +	bl	trap_reloc +	li	r7,.L_ProgramCheck - _start + _START_OFFSET +	bl	trap_reloc +	li	r7,.L_FPUnavailable - _start + _START_OFFSET +	bl	trap_reloc +	li	r7,.L_Decrementer - _start + _START_OFFSET +	bl	trap_reloc +	li	r7,.L_IntervalTimer - _start + _START_OFFSET +	li	r8,_end_of_vectors - _start + _START_OFFSET +2: +	bl	trap_reloc +	addi	r7,r7,0x100		/* next exception vector	*/ +	cmplw	0,r7,r8 +	blt	2b + +	lis	r7,0x0 +	mtspr	IVPR,r7 + +	mtlr	r4			/* restore link register	*/ +	blr + +.globl unlock_ram_in_cache +unlock_ram_in_cache: +	/* invalidate the INIT_RAM section */ +	lis	r3,(CONFIG_SYS_INIT_RAM_ADDR & ~(CONFIG_SYS_CACHELINE_SIZE-1))@h +	ori	r3,r3,(CONFIG_SYS_INIT_RAM_ADDR & ~(CONFIG_SYS_CACHELINE_SIZE-1))@l +	mfspr	r4,L1CFG0 +	andi.	r4,r4,0x1ff +	slwi	r4,r4,(10 - 1 - L1_CACHE_SHIFT) +	mtctr	r4 +1:	dcbi	r0,r3 +	addi	r3,r3,CONFIG_SYS_CACHELINE_SIZE +	bdnz	1b +	sync + +	/* Invalidate the TLB entries for the cache */ +	lis	r3,CONFIG_SYS_INIT_RAM_ADDR@h +	ori	r3,r3,CONFIG_SYS_INIT_RAM_ADDR@l +	tlbivax	0,r3 +	addi	r3,r3,0x1000 +	tlbivax	0,r3 +	addi	r3,r3,0x1000 +	tlbivax	0,r3 +	addi	r3,r3,0x1000 +	tlbivax	0,r3 +	isync +	blr + +.globl flush_dcache +flush_dcache: +	mfspr	r3,SPRN_L1CFG0 + +	rlwinm	r5,r3,9,3	/* Extract cache block size */ +	twlgti	r5,1		/* Only 32 and 64 byte cache blocks +				 * are currently defined. +				 */ +	li	r4,32 +	subfic	r6,r5,2		/* r6 = log2(1KiB / cache block size) - +				 *      log2(number of ways) +				 */ +	slw	r5,r4,r5	/* r5 = cache block size */ + +	rlwinm	r7,r3,0,0xff	/* Extract number of KiB in the cache */ +	mulli	r7,r7,13	/* An 8-way cache will require 13 +				 * loads per set. +				 */ +	slw	r7,r7,r6 + +	/* save off HID0 and set DCFA */ +	mfspr	r8,SPRN_HID0 +	ori	r9,r8,HID0_DCFA@l +	mtspr	SPRN_HID0,r9 +	isync + +	lis	r4,0 +	mtctr	r7 + +1:	lwz	r3,0(r4)	/* Load... */ +	add	r4,r4,r5 +	bdnz	1b + +	msync +	lis	r4,0 +	mtctr	r7 + +1:	dcbf	0,r4		/* ...and flush. */ +	add	r4,r4,r5 +	bdnz	1b + +	/* restore HID0 */ +	mtspr	SPRN_HID0,r8 +	isync + +	blr + +.globl setup_ivors +setup_ivors: + +#include "fixed_ivor.S" +	blr +#endif /* !CONFIG_NAND_SPL */ diff --git a/arch/powerpc/cpu/mpc85xx/tlb.c b/arch/powerpc/cpu/mpc85xx/tlb.c new file mode 100644 index 000000000..b3037acea --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/tlb.c @@ -0,0 +1,277 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. + * + * (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 + */ + +#include <common.h> +#include <asm/processor.h> +#include <asm/mmu.h> +#ifdef CONFIG_ADDR_MAP +#include <addr_map.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +void invalidate_tlb(u8 tlb) +{ +	if (tlb == 0) +		mtspr(MMUCSR0, 0x4); +	if (tlb == 1) +		mtspr(MMUCSR0, 0x2); +} + +void init_tlbs(void) +{ +	int i; + +	for (i = 0; i < num_tlb_entries; i++) { +		write_tlb(tlb_table[i].mas0, +			  tlb_table[i].mas1, +			  tlb_table[i].mas2, +			  tlb_table[i].mas3, +			  tlb_table[i].mas7); +	} + +	return ; +} + +#ifndef CONFIG_NAND_SPL +static inline void use_tlb_cam(u8 idx) +{ +	int i = idx / 32; +	int bit = idx % 32; + +	gd->used_tlb_cams[i] |= (1 << bit); +} + +static inline void free_tlb_cam(u8 idx) +{ +	int i = idx / 32; +	int bit = idx % 32; + +	gd->used_tlb_cams[i] &= ~(1 << bit); +} + +void init_used_tlb_cams(void) +{ +	int i; +	unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff; + +	for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++) +		gd->used_tlb_cams[i] = 0; + +	/* walk all the entries */ +	for (i = 0; i < num_cam; i++) { +		u32 _mas1; + +		mtspr(MAS0, FSL_BOOKE_MAS0(1, i, 0)); + +		asm volatile("tlbre;isync"); +		_mas1 = mfspr(MAS1); + +		/* if the entry isn't valid skip it */ +		if ((_mas1 & MAS1_VALID)) +			use_tlb_cam(i); +	} +} + +int find_free_tlbcam(void) +{ +	int i; +	u32 idx; + +	for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++) { +		idx = ffz(gd->used_tlb_cams[i]); + +		if (idx != 32) +			break; +	} + +	idx += i * 32; + +	if (idx >= CONFIG_SYS_NUM_TLBCAMS) +		return -1; + +	return idx; +} + +void set_tlb(u8 tlb, u32 epn, u64 rpn, +	     u8 perms, u8 wimge, +	     u8 ts, u8 esel, u8 tsize, u8 iprot) +{ +	u32 _mas0, _mas1, _mas2, _mas3, _mas7; + +	if (tlb == 1) +		use_tlb_cam(esel); + +	_mas0 = FSL_BOOKE_MAS0(tlb, esel, 0); +	_mas1 = FSL_BOOKE_MAS1(1, iprot, 0, ts, tsize); +	_mas2 = FSL_BOOKE_MAS2(epn, wimge); +	_mas3 = FSL_BOOKE_MAS3(rpn, 0, perms); +	_mas7 = FSL_BOOKE_MAS7(rpn); + +	write_tlb(_mas0, _mas1, _mas2, _mas3, _mas7); + +#ifdef CONFIG_ADDR_MAP +	if ((tlb == 1) && (gd->flags & GD_FLG_RELOC)) +		addrmap_set_entry(epn, rpn, (1UL << ((tsize * 2) + 10)), esel); +#endif +} + +void disable_tlb(u8 esel) +{ +	u32 _mas0, _mas1, _mas2, _mas3, _mas7; + +	free_tlb_cam(esel); + +	_mas0 = FSL_BOOKE_MAS0(1, esel, 0); +	_mas1 = 0; +	_mas2 = 0; +	_mas3 = 0; +	_mas7 = 0; + +	mtspr(MAS0, _mas0); +	mtspr(MAS1, _mas1); +	mtspr(MAS2, _mas2); +	mtspr(MAS3, _mas3); +#ifdef CONFIG_ENABLE_36BIT_PHYS +	mtspr(MAS7, _mas7); +#endif +	asm volatile("isync;msync;tlbwe;isync"); + +#ifdef CONFIG_ADDR_MAP +	if (gd->flags & GD_FLG_RELOC) +		addrmap_set_entry(0, 0, 0, esel); +#endif +} + +static void tlbsx (const volatile unsigned *addr) +{ +	__asm__ __volatile__ ("tlbsx 0,%0" : : "r" (addr), "m" (*addr)); +} + +/* return -1 if we didn't find anything */ +int find_tlb_idx(void *addr, u8 tlbsel) +{ +	u32 _mas0, _mas1; + +	/* zero out Search PID, AS */ +	mtspr(MAS6, 0); + +	tlbsx(addr); + +	_mas0 = mfspr(MAS0); +	_mas1 = mfspr(MAS1); + +	/* we found something, and its in the TLB we expect */ +	if ((MAS1_VALID & _mas1) && +		(MAS0_TLBSEL(tlbsel) == (_mas0 & MAS0_TLBSEL_MSK))) { +		return ((_mas0 & MAS0_ESEL_MSK) >> 16); +	} + +	return -1; +} + +#ifdef CONFIG_ADDR_MAP +void init_addr_map(void) +{ +	int i; +	unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff; + +	/* walk all the entries */ +	for (i = 0; i < num_cam; i++) { +		unsigned long epn; +		u32 tsize, _mas1; +		phys_addr_t rpn; + +		mtspr(MAS0, FSL_BOOKE_MAS0(1, i, 0)); + +		asm volatile("tlbre;isync"); +		_mas1 = mfspr(MAS1); + +		/* if the entry isn't valid skip it */ +		if (!(_mas1 & MAS1_VALID)) +			continue; + +		tsize = (_mas1 >> 8) & 0xf; +		epn = mfspr(MAS2) & MAS2_EPN; +		rpn = mfspr(MAS3) & MAS3_RPN; +#ifdef CONFIG_ENABLE_36BIT_PHYS +		rpn |= ((phys_addr_t)mfspr(MAS7)) << 32; +#endif + +		addrmap_set_entry(epn, rpn, (1UL << ((tsize * 2) + 10)), i); +	} + +	return ; +} +#endif + +unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) +{ +	int i; +	unsigned int tlb_size; +	unsigned int ram_tlb_address = (unsigned int)CONFIG_SYS_DDR_SDRAM_BASE; +	unsigned int max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xf; +	u64 size, memsize = (u64)memsize_in_meg << 20; + +	size = min(memsize, CONFIG_MAX_MEM_MAPPED); + +	/* Convert (4^max) kB to (2^max) bytes */ +	max_cam = max_cam * 2 + 10; + +	for (i = 0; size && i < 8; i++) { +		int ram_tlb_index = find_free_tlbcam(); +		u32 camsize = __ilog2_u64(size) & ~1U; +		u32 align = __ilog2(ram_tlb_address) & ~1U; + +		if (ram_tlb_index == -1) +			break; + +		if (align == -2) align = max_cam; +		if (camsize > align) +			camsize = align; + +		if (camsize > max_cam) +			camsize = max_cam; + +		tlb_size = (camsize - 10) / 2; + +		set_tlb(1, ram_tlb_address, ram_tlb_address, +			MAS3_SX|MAS3_SW|MAS3_SR, 0, +			0, ram_tlb_index, tlb_size, 1); + +		size -= 1ULL << camsize; +		memsize -= 1ULL << camsize; +		ram_tlb_address += 1UL << camsize; +	} + +	if (memsize) +		print_size(memsize, " left unmapped\n"); + +	/* +	 * Confirm that the requested amount of memory was mapped. +	 */ +	return memsize_in_meg; +} +#endif /* !CONFIG_NAND_SPL */ diff --git a/arch/powerpc/cpu/mpc85xx/traps.c b/arch/powerpc/cpu/mpc85xx/traps.c new file mode 100644 index 000000000..7e9666433 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/traps.c @@ -0,0 +1,325 @@ +/* + * linux/arch/powerpc/kernel/traps.c + * + * Copyright 2007 Freescale Semiconductor. + * Copyright (C) 2003 Motorola + * Modified by Xianghua Xiao(x.xiao@motorola.com) + * + * 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 <kgdb.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Returns 0 if exception not found and fixup otherwise.  */ +extern unsigned long search_exception_table(unsigned long); + +/* + * End of addressable memory.  This may be less than the actual + * amount of memory on the system if we're unable to keep all + * the memory mapped in. + */ +extern ulong get_effective_memsize(void); +#define END_OF_MEM (gd->bd->bi_memstart + get_effective_memsize()) + +static __inline__ void set_tsr(unsigned long val) +{ +	asm volatile("mtspr 0x150, %0" : : "r" (val)); +} + +static __inline__ unsigned long get_esr(void) +{ +	unsigned long val; +	asm volatile("mfspr %0, 0x03e" : "=r" (val) :); +	return val; +} + +#define ESR_MCI 0x80000000 +#define ESR_PIL 0x08000000 +#define ESR_PPR 0x04000000 +#define ESR_PTR 0x02000000 +#define ESR_DST 0x00800000 +#define ESR_DIZ 0x00400000 +#define ESR_U0F 0x00008000 + +#if defined(CONFIG_CMD_BEDBUG) +extern void do_bedbug_breakpoint(struct pt_regs *); +#endif + +/* + * Trap & Exception support + */ + +void +print_backtrace(unsigned long *sp) +{ +	int cnt = 0; +	unsigned long i; + +	printf("Call backtrace: "); +	while (sp) { +		if ((uint)sp > END_OF_MEM) +			break; + +		i = sp[1]; +		if (cnt++ % 7 == 0) +			printf("\n"); +		printf("%08lX ", i); +		if (cnt > 32) break; +		sp = (unsigned long *)*sp; +	} +	printf("\n"); +} + +void show_regs(struct pt_regs * regs) +{ +	int i; + +	printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n", +	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar); +	printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n", +	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, +	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, +	       regs->msr&MSR_IR ? 1 : 0, +	       regs->msr&MSR_DR ? 1 : 0); + +	printf("\n"); +	for (i = 0;  i < 32;  i++) { +		if ((i % 8) == 0) +		{ +			printf("GPR%02d: ", i); +		} + +		printf("%08lX ", regs->gpr[i]); +		if ((i % 8) == 7) +		{ +			printf("\n"); +		} +	} +} + + +void +_exception(int signr, struct pt_regs *regs) +{ +	show_regs(regs); +	print_backtrace((unsigned long *)regs->gpr[1]); +	panic("Exception in kernel pc %lx signal %d",regs->nip,signr); +} + +void +CritcalInputException(struct pt_regs *regs) +{ +	panic("Critical Input Exception"); +} + +int machinecheck_count = 0; +int machinecheck_error = 0; +void +MachineCheckException(struct pt_regs *regs) +{ +	unsigned long fixup; +	unsigned int mcsr, mcsrr0, mcsrr1, mcar; + +	/* 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; +	} + +	mcsrr0 = mfspr(SPRN_MCSRR0); +	mcsrr1 = mfspr(SPRN_MCSRR1); +	mcsr = mfspr(SPRN_MCSR); +	mcar = mfspr(SPRN_MCAR); + +	machinecheck_count++; +	machinecheck_error=1; + +#if defined(CONFIG_CMD_KGDB) +	if (debugger_exception_handler && (*debugger_exception_handler)(regs)) +		return; +#endif + +	printf("Machine check in kernel mode.\n"); +	printf("Caused by (from mcsr): "); +	printf("mcsr = 0x%08x\n", mcsr); +	if (mcsr & 0x80000000) +		printf("Machine check input pin\n"); +	if (mcsr & 0x40000000) +		printf("Instruction cache parity error\n"); +	if (mcsr & 0x20000000) +		printf("Data cache push parity error\n"); +	if (mcsr & 0x10000000) +		printf("Data cache parity error\n"); +	if (mcsr & 0x00000080) +		printf("Bus instruction address error\n"); +	if (mcsr & 0x00000040) +		printf("Bus Read address error\n"); +	if (mcsr & 0x00000020) +		printf("Bus Write address error\n"); +	if (mcsr & 0x00000010) +		printf("Bus Instruction data bus error\n"); +	if (mcsr & 0x00000008) +		printf("Bus Read data bus error\n"); +	if (mcsr & 0x00000004) +		printf("Bus Write bus error\n"); +	if (mcsr & 0x00000002) +		printf("Bus Instruction parity error\n"); +	if (mcsr & 0x00000001) +		printf("Bus Read parity error\n"); + +	show_regs(regs); +	printf("MCSR=0x%08x \tMCSRR0=0x%08x \nMCSRR1=0x%08x \tMCAR=0x%08x\n", +	       mcsr, mcsrr0, mcsrr1, mcar); +	print_backtrace((unsigned long *)regs->gpr[1]); +	if (machinecheck_count > 10) { +		panic("machine check count too high\n"); +	} + +	if (machinecheck_count > 1) { +		regs->nip += 4; /* skip offending instruction */ +		printf("Skipping current instr, Returning to 0x%08lx\n", +		       regs->nip); +	} else { +		printf("Returning back to 0x%08lx\n",regs->nip); +	} +} + +void +AlignmentException(struct pt_regs *regs) +{ +#if defined(CONFIG_CMD_KGDB) +	if (debugger_exception_handler && (*debugger_exception_handler)(regs)) +		return; +#endif + +	show_regs(regs); +	print_backtrace((unsigned long *)regs->gpr[1]); +	panic("Alignment Exception"); +} + +void +ProgramCheckException(struct pt_regs *regs) +{ +	long esr_val; + +#if defined(CONFIG_CMD_KGDB) +	if (debugger_exception_handler && (*debugger_exception_handler)(regs)) +		return; +#endif + +	show_regs(regs); + +	esr_val = get_esr(); +	if( esr_val & ESR_PIL ) +		printf( "** Illegal Instruction **\n" ); +	else if( esr_val & ESR_PPR ) +		printf( "** Privileged Instruction **\n" ); +	else if( esr_val & ESR_PTR ) +		printf( "** Trap Instruction **\n" ); + +	print_backtrace((unsigned long *)regs->gpr[1]); +	panic("Program Check Exception"); +} + +void +PITException(struct pt_regs *regs) +{ +	/* +	 * Reset PIT interrupt +	 */ +	set_tsr(0x0c000000); + +	/* +	 * Call timer_interrupt routine in interrupts.c +	 */ +	timer_interrupt(NULL); +} + + +void +UnknownException(struct pt_regs *regs) +{ +#if defined(CONFIG_CMD_KGDB) +	if (debugger_exception_handler && (*debugger_exception_handler)(regs)) +		return; +#endif + +	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", +	       regs->nip, regs->msr, regs->trap); +	_exception(0, regs); +} + +void +ExtIntException(struct pt_regs *regs) +{ +	volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR); + +	uint vect; + +#if defined(CONFIG_CMD_KGDB) +	if (debugger_exception_handler && (*debugger_exception_handler)(regs)) +		return; +#endif + +	printf("External Interrupt Exception at PC: %lx, SR: %lx, vector=%lx", +	       regs->nip, regs->msr, regs->trap); +	vect = pic->iack0; +	printf(" irq IACK0@%05x=%d\n",(int)&pic->iack0,vect); +	show_regs(regs); +	print_backtrace((unsigned long *)regs->gpr[1]); +} + +void +DebugException(struct pt_regs *regs) +{ +	printf("Debugger trap at @ %lx\n", regs->nip ); +	show_regs(regs); +#if defined(CONFIG_CMD_BEDBUG) +	do_bedbug_breakpoint( regs ); +#endif +} + +/* Probe an address by reading.	 If not present, return -1, otherwise + * return 0. + */ +int +addr_probe(uint *addr) +{ +	return 0; +} diff --git a/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds b/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds new file mode 100644 index 000000000..5fd3e6c8e --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds @@ -0,0 +1,137 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +/* Do we need any of these for elf? +   __DYNAMIC = 0;    */ +PHDRS +{ +  text PT_LOAD; +  bss PT_LOAD; +} + +SECTIONS +{ +  /* Read-only sections, merged into text segment: */ +  . = + SIZEOF_HEADERS; +  .interp : { *(.interp) } +  .hash          : { *(.hash)		} +  .dynsym        : { *(.dynsym)		} +  .dynstr        : { *(.dynstr)		} +  .rel.text      : { *(.rel.text)		} +  .rela.text     : { *(.rela.text)	} +  .rel.data      : { *(.rel.data)		} +  .rela.data     : { *(.rela.data)	} +  .rel.rodata    : { *(.rel.rodata)	} +  .rela.rodata   : { *(.rela.rodata)	} +  .rel.got       : { *(.rel.got)		} +  .rela.got      : { *(.rela.got)		} +  .rel.ctors     : { *(.rel.ctors)	} +  .rela.ctors    : { *(.rela.ctors)	} +  .rel.dtors     : { *(.rel.dtors)	} +  .rela.dtors    : { *(.rela.dtors)	} +  .rel.bss       : { *(.rel.bss)		} +  .rela.bss      : { *(.rela.bss)		} +  .rel.plt       : { *(.rel.plt)		} +  .rela.plt      : { *(.rela.plt)		} +  .init          : { *(.init)	} +  .plt : { *(.plt) } +  .text      : +  { +    *(.text) +    *(.got1) +   } :text +    _etext = .; +    PROVIDE (etext = .); +    .rodata    : +   { +    *(.eh_frame) +    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) +  } :text +  .fini      : { *(.fini)    } =0 +  .ctors     : { *(.ctors)   } +  .dtors     : { *(.dtors)   } + +  /* Read-write section, merged into data segment: */ +  . = (. + 0x00FF) & 0xFFFFFF00; +  _erotext = .; +  PROVIDE (erotext = .); +  .reloc   : +  { +    *(.got) +    _GOT2_TABLE_ = .; +    *(.got2) +    _FIXUP_TABLE_ = .; +    *(.fixup) +  } +  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; +  __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + +  .data    : +  { +    *(.data) +    *(.data1) +    *(.sdata) +    *(.sdata2) +    *(.dynamic) +    CONSTRUCTORS +  } +  _edata  =  .; +  PROVIDE (edata = .); + +  . = .; +  __u_boot_cmd_start = .; +  .u_boot_cmd : { *(.u_boot_cmd) } +  __u_boot_cmd_end = .; + +  . = .; +  __start___ex_table = .; +  __ex_table : { *(__ex_table) } +  __stop___ex_table = .; + +  . = ALIGN(256); +  __init_begin = .; +  .text.init : { *(.text.init) } +  .data.init : { *(.data.init) } +  . = ALIGN(256); +  __init_end = .; + +  .bootpg ADDR(.text) - 0x1000 : +  { +    arch/powerpc/cpu/mpc85xx/start.o	(.bootpg) +  } :text = 0xffff + +  . = ADDR(.text) + 0x80000; + +  __bss_start = .; +  .bss (NOLOAD)       : +  { +   *(.sbss) *(.scommon) +   *(.dynbss) +   *(.bss) +   *(COMMON) +  } :bss + +  . = ALIGN(4); +  _end = . ; +  PROVIDE (end = .); +} diff --git a/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds b/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds new file mode 100644 index 000000000..7d9cee98e --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds @@ -0,0 +1,67 @@ +/* + * (C) Copyright 2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de + * + * Copyright 2009 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +SECTIONS +{ +	. = 0xfff00000; +	.text : { +		*(.text) +	} +	_etext = .; + +	.reloc : { +		_GOT2_TABLE_ = .; +		*(.got2) +		_FIXUP_TABLE_ = .; +		*(.fixup) +	} +	__got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; +	__fixup_entries = (. - _FIXUP_TABLE_) >> 2; + +	. = ALIGN(8); +	.data : { +		*(.rodata*) +		*(.data*) +		*(.sdata*) +	} +	_edata  =  .; + +	. = ALIGN(8); +	__init_begin = .; +	__init_end = .; + +	.resetvec ADDR(.text) + 0xffc : { +		*(.resetvec) +	} = 0xffff + +	__bss_start = .; +	.bss : { +		*(.sbss) +		*(.bss) +	} +	_end = .; +} +ASSERT(__init_end <= 0xfff00ffc, "NAND bootstrap too big"); diff --git a/arch/powerpc/cpu/mpc85xx/u-boot.lds b/arch/powerpc/cpu/mpc85xx/u-boot.lds new file mode 100644 index 000000000..c88b1f35b --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/u-boot.lds @@ -0,0 +1,157 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef RESET_VECTOR_ADDRESS +#define RESET_VECTOR_ADDRESS	0xfffffffc +#endif + +OUTPUT_ARCH(powerpc) +/* Do we need any of these for elf? +   __DYNAMIC = 0;    */ +PHDRS +{ +  text PT_LOAD; +  bss PT_LOAD; +} + +SECTIONS +{ +  /* Read-only sections, merged into text segment: */ +  . = + SIZEOF_HEADERS; +  .interp : { *(.interp) } +  .hash          : { *(.hash)		} +  .dynsym        : { *(.dynsym)		} +  .dynstr        : { *(.dynstr)		} +  .rel.text      : { *(.rel.text)		} +  .rela.text     : { *(.rela.text)	} +  .rel.data      : { *(.rel.data)		} +  .rela.data     : { *(.rela.data)	} +  .rel.rodata    : { *(.rel.rodata)	} +  .rela.rodata   : { *(.rela.rodata)	} +  .rel.got       : { *(.rel.got)		} +  .rela.got      : { *(.rela.got)		} +  .rel.ctors     : { *(.rel.ctors)	} +  .rela.ctors    : { *(.rela.ctors)	} +  .rel.dtors     : { *(.rel.dtors)	} +  .rela.dtors    : { *(.rela.dtors)	} +  .rel.bss       : { *(.rel.bss)		} +  .rela.bss      : { *(.rela.bss)		} +  .rel.plt       : { *(.rel.plt)		} +  .rela.plt      : { *(.rela.plt)		} +  .init          : { *(.init)	} +  .plt : { *(.plt) } +  .text      : +  { +    *(.text) +    *(.got1) +   } :text +    _etext = .; +    PROVIDE (etext = .); +    .rodata    : +   { +    *(.eh_frame) +    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) +  } :text +  .fini      : { *(.fini)    } =0 +  .ctors     : { *(.ctors)   } +  .dtors     : { *(.dtors)   } + +  /* Read-write section, merged into data segment: */ +  . = (. + 0x00FF) & 0xFFFFFF00; +  _erotext = .; +  PROVIDE (erotext = .); +  .reloc   : +  { +    *(.got) +    _GOT2_TABLE_ = .; +    *(.got2) +    _FIXUP_TABLE_ = .; +    *(.fixup) +  } +  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; +  __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + +  .data    : +  { +    *(.data) +    *(.data1) +    *(.sdata) +    *(.sdata2) +    *(.dynamic) +    CONSTRUCTORS +  } +  _edata  =  .; +  PROVIDE (edata = .); + +  . = .; +  __u_boot_cmd_start = .; +  .u_boot_cmd : { *(.u_boot_cmd) } +  __u_boot_cmd_end = .; + +  . = .; +  __start___ex_table = .; +  __ex_table : { *(__ex_table) } +  __stop___ex_table = .; + +  . = ALIGN(256); +  __init_begin = .; +  .text.init : { *(.text.init) } +  .data.init : { *(.data.init) } +  . = ALIGN(256); +  __init_end = .; + +  .bootpg RESET_VECTOR_ADDRESS - 0xffc : +  { +    arch/powerpc/cpu/mpc85xx/start.o	(.bootpg) +  } :text = 0xffff + +  .resetvec RESET_VECTOR_ADDRESS : +  { +    *(.resetvec) +  } :text = 0xffff + +  . = RESET_VECTOR_ADDRESS + 0x4; + +  /* +   * Make sure that the bss segment isn't linked at 0x0, otherwise its +   * address won't be updated during relocation fixups.  Note that +   * this is a temporary fix.  Code to dynamically the fixup the bss +   * location will be added in the future.  When the bss relocation +   * fixup code is present this workaround should be removed. +   */ +#if (RESET_VECTOR_ADDRESS == 0xfffffffc) +  . |= 0x10; +#endif + +  __bss_start = .; +  .bss (NOLOAD)       : +  { +   *(.sbss) *(.scommon) +   *(.dynbss) +   *(.bss) +   *(COMMON) +  } :bss + +  . = ALIGN(4); +  _end = . ; +  PROVIDE (end = .); +} |