diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc512x')
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/Makefile | 63 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/asm-offsets.h | 15 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/config.mk | 29 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/cpu.c | 216 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/cpu_init.c | 92 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/diu.c | 188 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/fixed_sdram.c | 152 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/i2c.c | 403 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/ide.c | 128 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/iim.c | 394 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/interrupts.c | 61 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/iopin.c | 49 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/pci.c | 227 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/serial.c | 193 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/speed.c | 156 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/start.S | 711 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/traps.c | 212 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc512x/u-boot.lds | 120 | 
18 files changed, 3409 insertions, 0 deletions
| diff --git a/arch/powerpc/cpu/mpc512x/Makefile b/arch/powerpc/cpu/mpc512x/Makefile new file mode 100644 index 000000000..1719c66e8 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/Makefile @@ -0,0 +1,63 @@ +# +# (C) Copyright 2007-2009 DENX Software Engineering +# +# 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 + +$(shell mkdir -p $(OBJTREE)/board/freescale/common) + +LIB	= $(obj)lib$(CPU).a + +START	= start.o +COBJS-y	:= cpu.o +COBJS-y	+= traps.o +COBJS-y += cpu_init.o +COBJS-y += fixed_sdram.o +COBJS-y += i2c.o +COBJS-y += interrupts.o +COBJS-y += iopin.o +COBJS-y += serial.o +COBJS-y += speed.o +COBJS-${CONFIG_FSL_DIU_FB} += diu.o +COBJS-${CONFIG_FSL_DIU_FB} += ../../../../board/freescale/common/fsl_diu_fb.o +COBJS-${CONFIG_FSL_DIU_FB} += ../../../../board/freescale/common/fsl_logo_bmp.o +COBJS-${CONFIG_CMD_IDE} += ide.o +COBJS-${CONFIG_IIM} += iim.o +COBJS-$(CONFIG_PCI) += pci.o + +COBJS	:= $(COBJS-y) +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/mpc512x/asm-offsets.h b/arch/powerpc/cpu/mpc512x/asm-offsets.h new file mode 100644 index 000000000..957d4be2d --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/asm-offsets.h @@ -0,0 +1,15 @@ +/* + * needed for arch/powerpc/cpu/mpc512x/start.S + * + * These should be auto-generated + */ +#define LPCS0AW			0x0024 +#define SRAMBAR			0x00C4 +#define SWCRR			0x0904 +#define LPC_OFFSET		0x10000 +#define CS0_CONFIG		0x00000 +#define CS_CTRL			0x00020 +#define CS_CTRL_ME		0x01000000	/* CS Master Enable bit */ + +#define EXC_OFF_SYS_RESET	0x0100 +#define	_START_OFFSET		EXC_OFF_SYS_RESET diff --git a/arch/powerpc/cpu/mpc512x/config.mk b/arch/powerpc/cpu/mpc512x/config.mk new file mode 100644 index 000000000..b29edb1b3 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/config.mk @@ -0,0 +1,29 @@ +# +# (C) Copyright 2007-2009 DENX Software Engineering +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +PLATFORM_RELFLAGS += -fPIC -meabi + +PLATFORM_CPPFLAGS += -DCONFIG_MPC512X -DCONFIG_E300 \ +			-ffixed-r2 -msoft-float -mcpu=603e + +# Use default linker script. +# A board port can override this setting in board/*/config.mk +LDSCRIPT := $(SRCTREE)/arch/powerpc/cpu/mpc512x/u-boot.lds diff --git a/arch/powerpc/cpu/mpc512x/cpu.c b/arch/powerpc/cpu/mpc512x/cpu.c new file mode 100644 index 000000000..09cbd2024 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/cpu.c @@ -0,0 +1,216 @@ +/* + * (C) Copyright 2007-2010 DENX Software Engineering + * Copyright (C) 2004-2006 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 + */ + +/* + * CPU specific code for the MPC512x family. + * + * Derived from the MPC83xx code. + */ + +#include <common.h> +#include <command.h> +#include <net.h> +#include <netdev.h> +#include <asm/processor.h> +#include <asm/io.h> + +#if defined(CONFIG_OF_LIBFDT) +#include <fdt_support.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +int checkcpu (void) +{ +	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; +	ulong clock = gd->cpu_clk; +	u32 pvr = get_pvr (); +	u32 spridr = in_be32(&immr->sysconf.spridr); +	char buf1[32], buf2[32]; + +	puts ("CPU:   "); + +	switch (spridr & 0xffff0000) { +	case SPR_5121E: +		puts ("MPC5121e "); +		break; +	default: +		printf ("Unknown part ID %08x ", spridr & 0xffff0000); +	} +	printf ("rev. %d.%d, Core ", SVR_MJREV (spridr), SVR_MNREV (spridr)); + +	switch (pvr & 0xffff0000) { +	case PVR_E300C4: +		puts ("e300c4 "); +		break; +	default: +		puts ("unknown "); +	} +	printf ("at %s MHz, CSB at %s MHz (RSR=0x%04lx)\n", +		strmhz(buf1, clock), +		strmhz(buf2, gd->csb_clk), +		gd->reset_status & 0xffff); +	return 0; +} + + +int +do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ +	ulong msr; +	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + +	/* Interrupts and MMU off */ +	__asm__ __volatile__ ("mfmsr    %0":"=r" (msr):); + +	msr &= ~( MSR_EE | MSR_IR | MSR_DR); +	__asm__ __volatile__ ("mtmsr    %0"::"r" (msr)); + +	/* +	 * Enable Reset Control Reg - "RSTE" is the magic word that let us go +	 */ +	out_be32(&immap->reset.rpr, 0x52535445); + +	/* Verify Reset Control Reg is enabled */ +	while (!(in_be32(&immap->reset.rcer) & RCER_CRE)) +		; + +	printf ("Resetting the board.\n"); +	udelay(200); + +	/* Perform reset */ +	out_be32(&immap->reset.rcr, RCR_SWHR); + +	/* Unreached... */ +	return 1; +} + + +/* + * Get timebase clock frequency (like cpu_clk in Hz) + */ +unsigned long get_tbclk (void) +{ +	ulong tbclk; + +	tbclk = (gd->bus_clk + 3L) / 4L; + +	return tbclk; +} + + +#if defined(CONFIG_WATCHDOG) +void watchdog_reset (void) +{ +	int re_enable = disable_interrupts (); + +	/* Reset watchdog */ +	volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; +	out_be32(&immr->wdt.swsrr, 0x556c); +	out_be32(&immr->wdt.swsrr, 0xaa39); + +	if (re_enable) +		enable_interrupts (); +} +#endif + +#ifdef CONFIG_OF_LIBFDT + +#ifdef CONFIG_OF_SUPPORT_OLD_DEVICE_TREES +/* + * fdt setup for old device trees + * fix up + * 	cpu clocks + * 	soc clocks + * 	ethernet addresses + */ +static void old_ft_cpu_setup(void *blob, bd_t *bd) +{ +	/* +	 * avoid fixing up by path because that +	 * produces scary error messages +	 */ +	uchar enetaddr[6]; + +	/* +	 * old device trees have ethernet nodes with +	 * device_type = "network" +	 */ +	eth_getenv_enetaddr("ethaddr", enetaddr); +	do_fixup_by_prop(blob, "device_type", "network", 8, +		"local-mac-address", enetaddr, 6, 0); +	do_fixup_by_prop(blob, "device_type", "network", 8, +		"address", enetaddr, 6, 0); +	/* +	 * old device trees have soc nodes with +	 * device_type = "soc" +	 */ +	do_fixup_by_prop_u32(blob, "device_type", "soc", 4, +		"bus-frequency", bd->bi_ipsfreq, 0); +} +#endif + +static void ft_clock_setup(void *blob, bd_t *bd) +{ +	char *cpu_path = "/cpus/" OF_CPU; + +	/* +	 * fixup cpu clocks using path +	 */ +	do_fixup_by_path_u32(blob, cpu_path, +		"timebase-frequency", OF_TBCLK, 1); +	do_fixup_by_path_u32(blob, cpu_path, +		"bus-frequency", bd->bi_busfreq, 1); +	do_fixup_by_path_u32(blob, cpu_path, +		"clock-frequency", bd->bi_intfreq, 1); +	/* +	 * fixup soc clocks using compatible +	 */ +	do_fixup_by_compat_u32(blob, OF_SOC_COMPAT, +		"bus-frequency", bd->bi_ipsfreq, 1); +} + +void ft_cpu_setup(void *blob, bd_t *bd) +{ +#ifdef CONFIG_OF_SUPPORT_OLD_DEVICE_TREES +	old_ft_cpu_setup(blob, bd); +#endif +	ft_clock_setup(blob, bd); +#ifdef CONFIG_HAS_ETH0 +	fdt_fixup_ethernet(blob); +#endif +	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize); +} +#endif + +#ifdef CONFIG_MPC512x_FEC +/* Default initializations for FEC controllers.  To override, + * create a board-specific function called: + * 	int board_eth_init(bd_t *bis) + */ + +int cpu_eth_init(bd_t *bis) +{ +	return mpc512x_fec_initialize(bis); +} +#endif diff --git a/arch/powerpc/cpu/mpc512x/cpu_init.c b/arch/powerpc/cpu/mpc512x/cpu_init.c new file mode 100644 index 000000000..fe6beaf84 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/cpu_init.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2004-2006 Freescale Semiconductor, Inc. + * Copyright (C) 2007-2009 DENX Software Engineering + * + * 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 + * + * Derived from the MPC83xx code. + * + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Set up the memory map, initialize registers, + */ +void cpu_init_f (volatile immap_t * im) +{ +	u32 ips_div; + +	/* 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 */ +	memset ((void *) gd, 0, sizeof (gd_t)); + +	/* system performance tweaking */ + +#ifdef CONFIG_SYS_ACR_PIPE_DEP +	/* Arbiter pipeline depth */ +	out_be32(&im->arbiter.acr, +		(im->arbiter.acr & ~ACR_PIPE_DEP) | +		(CONFIG_SYS_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT) +	); +#endif + +#ifdef CONFIG_SYS_ACR_RPTCNT +	/* Arbiter repeat count */ +	out_be32(im->arbiter.acr, +		(im->arbiter.acr & ~(ACR_RPTCNT)) | +		(CONFIG_SYS_ACR_RPTCNT << ACR_RPTCNT_SHIFT) +	); +#endif + +	/* RSR - Reset Status Register - clear all status */ +	gd->reset_status = im->reset.rsr; +	out_be32(&im->reset.rsr, ~RSR_RES); + +	/* +	 * RMR - Reset Mode Register - enable checkstop reset +	 */ +	out_be32(&im->reset.rmr, RMR_CSRE & (1 << RMR_CSRE_SHIFT)); + +	/* Set IPS-CSB divider: IPS = 1/2 CSB */ +	ips_div = in_be32(&im->clk.scfr[0]); +	ips_div &= ~(SCFR1_IPS_DIV_MASK); +	ips_div |= SCFR1_IPS_DIV << SCFR1_IPS_DIV_SHIFT; +	out_be32(&im->clk.scfr[0], ips_div); + +	/* +	 * Enable Time Base/Decrementer +	 * +	 * NOTICE: TB needs to be enabled as early as possible in order to +	 * have udelay() working; if not enabled, usually leads to a hang, like +	 * during FLASH chip identification etc. +	 */ +	setbits_be32(&im->sysconf.spcr, SPCR_TBEN); +} + +int cpu_init_r (void) +{ +	return 0; +} diff --git a/arch/powerpc/cpu/mpc512x/diu.c b/arch/powerpc/cpu/mpc512x/diu.c new file mode 100644 index 000000000..93611615f --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/diu.c @@ -0,0 +1,188 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * York Sun <yorksun@freescale.com> + * + * FSL DIU Framebuffer driver + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <asm/io.h> + +#include "../../../../board/freescale/common/fsl_diu_fb.h" + +#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE) +#include <stdio_dev.h> +#include <video_fb.h> +#endif + +#ifdef CONFIG_FSL_DIU_LOGO_BMP +extern unsigned int FSL_Logo_BMP[]; +#else +#define FSL_Logo_BMP NULL +#endif + +static int xres, yres; + +void diu_set_pixel_clock(unsigned int pixclock) +{ +	volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; +	volatile clk512x_t *clk = &immap->clk; +	volatile unsigned int *clkdvdr = &clk->scfr[0]; +	unsigned long speed_ccb, temp, pixval; + +	speed_ccb = get_bus_freq(0) * 4; +	temp = 1000000000/pixclock; +	temp *= 1000; +	pixval = speed_ccb / temp; +	debug("DIU pixval = %lu\n", pixval); + +	/* Modify PXCLK in GUTS CLKDVDR */ +	debug("DIU: Current value of CLKDVDR = 0x%08x\n", in_be32(clkdvdr)); +	temp = in_be32(clkdvdr) & 0xFFFFFF00; +	out_be32(clkdvdr, temp | (pixval & 0xFF)); +	debug("DIU: Modified value of CLKDVDR = 0x%08x\n", in_be32(clkdvdr)); +} + +char *valid_bmp(char *addr) +{ +	unsigned long h_addr; + +	h_addr = simple_strtoul(addr, NULL, 16); +	if (h_addr < CONFIG_SYS_FLASH_BASE || +			h_addr >= (CONFIG_SYS_FLASH_BASE + CONFIG_SYS_FLASH_SIZE - 1)) { +		printf("bmp addr %lx is not a valid flash address\n", h_addr); +		return 0; +	} else if ((*(char *)(h_addr) != 'B') || (*(char *)(h_addr+1) != 'M')) { +		printf("bmp addr is not a bmp\n"); +		return 0; +	} else +		return (char *)h_addr; +} + +int mpc5121_diu_init(void) +{ +	unsigned int pixel_format; +	char *bmp = NULL; +	char *bmp_env; + +	xres = 1024; +	yres = 768; +	pixel_format = 0x88883316; + +	debug("mpc5121_diu_init\n"); +	bmp_env = getenv("diu_bmp_addr"); +	if (bmp_env) { +		bmp = valid_bmp(bmp_env); +	} +	if (!bmp) +		bmp = (char *)FSL_Logo_BMP; +	return fsl_diu_init(xres, pixel_format, 0, (unsigned char *)bmp); +} + +int mpc5121diu_init_show_bmp(cmd_tbl_t *cmdtp, +			     int flag, int argc, char *argv[]) +{ +	unsigned int addr; + +	if (argc < 2) { +		cmd_usage(cmdtp); +		return 1; +	} + +	if (!strncmp(argv[1], "init", 4)) { +#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE) +		fsl_diu_clear_screen(); +		drv_video_init(); +#else +		return mpc5121_diu_init(); +#endif +	} else { +		addr = simple_strtoul(argv[1], NULL, 16); +		fsl_diu_clear_screen(); +		fsl_diu_display_bmp((unsigned char *)addr, 0, 0, 0); +	} + +	return 0; +} + +U_BOOT_CMD( +	diufb, CONFIG_SYS_MAXARGS, 1, mpc5121diu_init_show_bmp, +	"Init or Display BMP file", +	"init\n    - initialize DIU\n" +	"addr\n    - display bmp at address 'addr'" +	); + + +#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE) + +/* + * The Graphic Device + */ +GraphicDevice ctfb; +void *video_hw_init(void) +{ +	GraphicDevice *pGD = (GraphicDevice *) &ctfb; +	struct fb_info *info; + +	if (mpc5121_diu_init() < 0) +		return NULL; + +	/* fill in Graphic device struct */ +	sprintf(pGD->modeIdent, "%dx%dx%d %dkHz %dHz", +		xres, yres, 32, 64, 60); + +	pGD->frameAdrs = (unsigned int)fsl_fb_open(&info); +	pGD->winSizeX = xres; +	pGD->winSizeY = yres - info->logo_height; +	pGD->plnSizeX = pGD->winSizeX; +	pGD->plnSizeY = pGD->winSizeY; + +	pGD->gdfBytesPP = 4; +	pGD->gdfIndex = GDF_32BIT_X888RGB; + +	pGD->isaBase = 0; +	pGD->pciBase = 0; +	pGD->memSize = info->screen_size - info->logo_size; + +	/* Cursor Start Address */ +	pGD->dprBase = 0; +	pGD->vprBase = 0; +	pGD->cprBase = 0; + +	return (void *)pGD; +} + +/** +  * Set the LUT +  * +  * @index: color number +  * @r: red +  * @b: blue +  * @g: green +  */ +void video_set_lut +	(unsigned int index, unsigned char r, unsigned char g, unsigned char b) +{ +	return; +} + +#endif /* defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE) */ diff --git a/arch/powerpc/cpu/mpc512x/fixed_sdram.c b/arch/powerpc/cpu/mpc512x/fixed_sdram.c new file mode 100644 index 000000000..442b5fc91 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/fixed_sdram.c @@ -0,0 +1,152 @@ +/* + * (C) Copyright 2007-2009 DENX Software Engineering + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/mpc512x.h> + +/* + * MDDRC Config Runtime Settings + */ +ddr512x_config_t default_mddrc_config = { +	.ddr_sys_config   = CONFIG_SYS_MDDRC_SYS_CFG, +	.ddr_time_config0 = CONFIG_SYS_MDDRC_TIME_CFG0, +	.ddr_time_config1 = CONFIG_SYS_MDDRC_TIME_CFG1, +	.ddr_time_config2 = CONFIG_SYS_MDDRC_TIME_CFG2, +}; + +u32 default_init_seq[] = { +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_PCHG_ALL, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_RFSH, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_RFSH, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_MICRON_INIT_DEV_OP, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_EM2, +	CONFIG_SYS_DDRCMD_NOP, +	CONFIG_SYS_DDRCMD_PCHG_ALL, +	CONFIG_SYS_DDRCMD_EM2, +	CONFIG_SYS_DDRCMD_EM3, +	CONFIG_SYS_DDRCMD_EN_DLL, +	CONFIG_SYS_MICRON_INIT_DEV_OP, +	CONFIG_SYS_DDRCMD_PCHG_ALL, +	CONFIG_SYS_DDRCMD_RFSH, +	CONFIG_SYS_MICRON_INIT_DEV_OP, +	CONFIG_SYS_DDRCMD_OCD_DEFAULT, +	CONFIG_SYS_DDRCMD_PCHG_ALL, +	CONFIG_SYS_DDRCMD_NOP +}; + +/* + * fixed sdram init: + * The board doesn't use memory modules that have serial presence + * detect or similar mechanism for discovery of the DRAM settings + */ +long int fixed_sdram(ddr512x_config_t *mddrc_config, +			u32 *dram_init_seq, int seq_sz) +{ +	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; +	u32 msize = CONFIG_SYS_DDR_SIZE * 1024 * 1024; +	u32 msize_log2 = __ilog2(msize); +	u32 i; + +	/* take default settings and init sequence if necessary */ +	if (mddrc_config == NULL) +		mddrc_config = &default_mddrc_config; +	if (dram_init_seq == NULL) { +		dram_init_seq = default_init_seq; +		seq_sz = sizeof(default_init_seq)/sizeof(u32); +	} + +	/* Initialize IO Control */ +	out_be32(&im->io_ctrl.io_control_mem, IOCTRL_MUX_DDR); + +	/* Initialize DDR Local Window */ +	out_be32(&im->sysconf.ddrlaw.bar, CONFIG_SYS_DDR_BASE & 0xFFFFF000); +	out_be32(&im->sysconf.ddrlaw.ar, msize_log2 - 1); +	sync_law(&im->sysconf.ddrlaw.ar); + +	/* DDR Enable */ +	out_be32(&im->mddrc.ddr_sys_config, MDDRC_SYS_CFG_EN); + +	/* Initialize DDR Priority Manager */ +	out_be32(&im->mddrc.prioman_config1, CONFIG_SYS_MDDRCGRP_PM_CFG1); +	out_be32(&im->mddrc.prioman_config2, CONFIG_SYS_MDDRCGRP_PM_CFG2); +	out_be32(&im->mddrc.hiprio_config, CONFIG_SYS_MDDRCGRP_HIPRIO_CFG); +	out_be32(&im->mddrc.lut_table0_main_upper, CONFIG_SYS_MDDRCGRP_LUT0_MU); +	out_be32(&im->mddrc.lut_table0_main_lower, CONFIG_SYS_MDDRCGRP_LUT0_ML); +	out_be32(&im->mddrc.lut_table1_main_upper, CONFIG_SYS_MDDRCGRP_LUT1_MU); +	out_be32(&im->mddrc.lut_table1_main_lower, CONFIG_SYS_MDDRCGRP_LUT1_ML); +	out_be32(&im->mddrc.lut_table2_main_upper, CONFIG_SYS_MDDRCGRP_LUT2_MU); +	out_be32(&im->mddrc.lut_table2_main_lower, CONFIG_SYS_MDDRCGRP_LUT2_ML); +	out_be32(&im->mddrc.lut_table3_main_upper, CONFIG_SYS_MDDRCGRP_LUT3_MU); +	out_be32(&im->mddrc.lut_table3_main_lower, CONFIG_SYS_MDDRCGRP_LUT3_ML); +	out_be32(&im->mddrc.lut_table4_main_upper, CONFIG_SYS_MDDRCGRP_LUT4_MU); +	out_be32(&im->mddrc.lut_table4_main_lower, CONFIG_SYS_MDDRCGRP_LUT4_ML); +	out_be32(&im->mddrc.lut_table0_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT0_AU); +	out_be32(&im->mddrc.lut_table0_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT0_AL); +	out_be32(&im->mddrc.lut_table1_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT1_AU); +	out_be32(&im->mddrc.lut_table1_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT1_AL); +	out_be32(&im->mddrc.lut_table2_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT2_AU); +	out_be32(&im->mddrc.lut_table2_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT2_AL); +	out_be32(&im->mddrc.lut_table3_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT3_AU); +	out_be32(&im->mddrc.lut_table3_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT3_AL); +	out_be32(&im->mddrc.lut_table4_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT4_AU); +	out_be32(&im->mddrc.lut_table4_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT4_AL); + +	/* +	 * Initialize MDDRC +	 *  put MDDRC in CMD mode and +	 *  set the max time between refreshes to 0 during init process +	 */ +	out_be32(&im->mddrc.ddr_sys_config, +		mddrc_config->ddr_sys_config | MDDRC_SYS_CFG_CMD_MASK); +	out_be32(&im->mddrc.ddr_time_config0, +		mddrc_config->ddr_time_config0 & MDDRC_REFRESH_ZERO_MASK); +	out_be32(&im->mddrc.ddr_time_config1, +		mddrc_config->ddr_time_config1); +	out_be32(&im->mddrc.ddr_time_config2, +		mddrc_config->ddr_time_config2); + +	/* Initialize DDR with either default or supplied init sequence */ +	for (i = 0; i < seq_sz; i++) +		out_be32(&im->mddrc.ddr_command, dram_init_seq[i]); + +	/* Start MDDRC */ +	out_be32(&im->mddrc.ddr_time_config0, mddrc_config->ddr_time_config0); +	out_be32(&im->mddrc.ddr_sys_config, mddrc_config->ddr_sys_config); + +	return msize; +} diff --git a/arch/powerpc/cpu/mpc512x/i2c.c b/arch/powerpc/cpu/mpc512x/i2c.c new file mode 100644 index 000000000..e2d909751 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/i2c.c @@ -0,0 +1,403 @@ +/* + * (C) Copyright 2003 - 2009 + * 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 + * + * Based on the MPC5xxx code. + */ + +#include <common.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_HARD_I2C + +#include <i2c.h> + +/* by default set I2C bus 0 active */ +static unsigned int bus_num __attribute__ ((section (".data"))) = 0; + +#define I2C_TIMEOUT	100 +#define I2C_RETRIES	3 + +struct mpc512x_i2c_tap { +	int scl2tap; +	int tap2tap; +}; + +static int  mpc_reg_in(volatile u32 *reg); +static void mpc_reg_out(volatile u32 *reg, int val, int mask); +static int  wait_for_bb(void); +static int  wait_for_pin(int *status); +static int  do_address(uchar chip, char rdwr_flag); +static int  send_bytes(uchar chip, char *buf, int len); +static int  receive_bytes(uchar chip, char *buf, int len); +static int  mpc_get_fdr(int); + +static int mpc_reg_in (volatile u32 *reg) +{ +	int ret = in_be32(reg) >> 24; + +	return ret; +} + +static void mpc_reg_out (volatile u32 *reg, int val, int mask) +{ +	if (!mask) { +		out_be32(reg, val << 24); +	} else { +		clrsetbits_be32(reg, mask << 24, (val & mask) << 24); +	} +} + +static int wait_for_bb (void) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num]; +	int timeout = I2C_TIMEOUT; +	int status; + +	status = mpc_reg_in (®s->msr); + +	while (timeout-- && (status & I2C_BB)) { +		volatile int temp; +		mpc_reg_out (®s->mcr, I2C_STA, I2C_STA); +		temp = mpc_reg_in (®s->mdr); +		mpc_reg_out (®s->mcr, 0, I2C_STA); +		mpc_reg_out (®s->mcr, 0, 0); +		mpc_reg_out (®s->mcr, I2C_EN, 0); + +		udelay (1000); +		status = mpc_reg_in (®s->msr); +	} + +	return (status & I2C_BB); +} + +static int wait_for_pin (int *status) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num]; +	int timeout = I2C_TIMEOUT; + +	*status = mpc_reg_in (®s->msr); + +	while (timeout-- && !(*status & I2C_IF)) { +		udelay (1000); +		*status = mpc_reg_in (®s->msr); +	} + +	if (!(*status & I2C_IF)) { +		return -1; +	} + +	mpc_reg_out (®s->msr, 0, I2C_IF); + +	return 0; +} + +static int do_address (uchar chip, char rdwr_flag) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num]; +	int status; + +	chip <<= 1; + +	if (rdwr_flag) { +		chip |= 1; +	} + +	mpc_reg_out (®s->mcr, I2C_TX, I2C_TX); +	mpc_reg_out (®s->mdr, chip, 0); + +	if (wait_for_pin (&status)) { +		return -2; +	} + +	if (status & I2C_RXAK) { +		return -3; +	} + +	return 0; +} + +static int send_bytes (uchar chip, char *buf, int len) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num]; +	int wrcount; +	int status; + +	for (wrcount = 0; wrcount < len; ++wrcount) { + +		mpc_reg_out (®s->mdr, buf[wrcount], 0); + +		if (wait_for_pin (&status)) { +			break; +		} + +		if (status & I2C_RXAK) { +			break; +		} + +	} + +	return !(wrcount == len); +} + +static int receive_bytes (uchar chip, char *buf, int len) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num]; +	int dummy   = 1; +	int rdcount = 0; +	int status; +	int i; + +	mpc_reg_out (®s->mcr, 0, I2C_TX); + +	for (i = 0; i < len; ++i) { +		buf[rdcount] = mpc_reg_in (®s->mdr); + +		if (dummy) { +			dummy = 0; +		} else { +			rdcount++; +		} + +		if (wait_for_pin (&status)) { +			return -4; +		} +	} + +	mpc_reg_out (®s->mcr, I2C_TXAK, I2C_TXAK); +	buf[rdcount++] = mpc_reg_in (®s->mdr); + +	if (wait_for_pin (&status)) { +		return -5; +	} + +	mpc_reg_out (®s->mcr, 0, I2C_TXAK); + +	return 0; +} + +/**************** I2C API ****************/ + +void i2c_init (int speed, int saddr) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	int i; + +	for (i = 0; i < I2C_BUS_CNT; i++){ +		volatile i2c512x_dev_t *regs = &im->i2c.dev[i]; + +		mpc_reg_out (®s->mcr, 0, 0); + +		/* Set clock */ +		mpc_reg_out (®s->mfdr, mpc_get_fdr (speed), 0); +		mpc_reg_out (®s->madr, saddr << 1, 0); + +		/* Enable module */ +		mpc_reg_out (®s->mcr, I2C_EN, I2C_INIT_MASK); +		mpc_reg_out (®s->msr, 0, I2C_IF); +	} + +	/* Disable interrupts */ +	out_be32(&im->i2c.icr, 0); + +	/* Turn off filters */ +	out_be32(&im->i2c.mifr, 0); +} + +static int mpc_get_fdr (int speed) +{ +	static int fdr = -1; + +	if (fdr == -1) { +		ulong best_speed = 0; +		ulong divider; +		ulong ips, scl; +		ulong bestmatch = 0xffffffffUL; +		int best_i = 0, best_j = 0, i, j; +		int SCL_Tap[] = { 9, 10, 12, 15, 5, 6, 7, 8}; +		struct mpc512x_i2c_tap scltap[] = { +			{4, 1}, +			{4, 2}, +			{6, 4}, +			{6, 8}, +			{14, 16}, +			{30, 32}, +			{62, 64}, +			{126, 128} +		}; + +		ips = gd->ips_clk; +		for (i = 7; i >= 0; i--) { +			for (j = 7; j >= 0; j--) { +				scl = 2 * (scltap[j].scl2tap + +					   (SCL_Tap[i] - 1) * scltap[j].tap2tap +					   + 2); +				if (ips <= speed*scl) { +					if ((speed*scl - ips) < bestmatch) { +						bestmatch = speed*scl - ips; +						best_i = i; +						best_j = j; +						best_speed = ips/scl; +					} +				} +			} +		} +		divider = (best_i & 3) | ((best_i & 4) << 3) | (best_j << 2); +		if (gd->flags & GD_FLG_RELOC) { +			fdr = divider; +		} else { +			debug("%ld kHz, \n", best_speed / 1000); +			return divider; +		} +	} + +	return fdr; +} + +int i2c_probe (uchar chip) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num]; +	int i; + +	for (i = 0; i < I2C_RETRIES; i++) { +		mpc_reg_out (®s->mcr, I2C_STA, I2C_STA); + +		if (! do_address (chip, 0)) { +			mpc_reg_out (®s->mcr, 0, I2C_STA); +			udelay (500); +			break; +		} + +		mpc_reg_out (®s->mcr, 0, I2C_STA); +		udelay (500); +	} + +	return (i == I2C_RETRIES); +} + +int i2c_read (uchar chip, uint addr, int alen, uchar *buf, int len) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num]; +	char xaddr[4]; +	int ret = -1; + +	xaddr[0] = (addr >> 24) & 0xFF; +	xaddr[1] = (addr >> 16) & 0xFF; +	xaddr[2] = (addr >>  8) & 0xFF; +	xaddr[3] =  addr	& 0xFF; + +	if (wait_for_bb ()) { +		printf ("i2c_read: bus is busy\n"); +		goto Done; +	} + +	mpc_reg_out (®s->mcr, I2C_STA, I2C_STA); +	if (do_address (chip, 0)) { +		printf ("i2c_read: failed to address chip\n"); +		goto Done; +	} + +	if (send_bytes (chip, &xaddr[4-alen], alen)) { +		printf ("i2c_read: send_bytes failed\n"); +		goto Done; +	} + +	mpc_reg_out (®s->mcr, I2C_RSTA, I2C_RSTA); +	if (do_address (chip, 1)) { +		printf ("i2c_read: failed to address chip\n"); +		goto Done; +	} + +	if (receive_bytes (chip, (char *)buf, len)) { +		printf ("i2c_read: receive_bytes failed\n"); +		goto Done; +	} + +	ret = 0; +Done: +	mpc_reg_out (®s->mcr, 0, I2C_STA); +	return ret; +} + +int i2c_write (uchar chip, uint addr, int alen, uchar *buf, int len) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num]; +	char xaddr[4]; +	int ret = -1; + +	xaddr[0] = (addr >> 24) & 0xFF; +	xaddr[1] = (addr >> 16) & 0xFF; +	xaddr[2] = (addr >>  8) & 0xFF; +	xaddr[3] =  addr	& 0xFF; + +	if (wait_for_bb ()) { +		printf ("i2c_write: bus is busy\n"); +		goto Done; +	} + +	mpc_reg_out (®s->mcr, I2C_STA, I2C_STA); +	if (do_address (chip, 0)) { +		printf ("i2c_write: failed to address chip\n"); +		goto Done; +	} + +	if (send_bytes (chip, &xaddr[4-alen], alen)) { +		printf ("i2c_write: send_bytes failed\n"); +		goto Done; +	} + +	if (send_bytes (chip, (char *)buf, len)) { +		printf ("i2c_write: send_bytes failed\n"); +		goto Done; +	} + +	ret = 0; +Done: +	mpc_reg_out (®s->mcr, 0, I2C_STA); +	return ret; +} + +int i2c_set_bus_num (unsigned int bus) +{ +	if (bus >= I2C_BUS_CNT) { +		return -1; +	} +	bus_num = bus; + +	return 0; +} + +unsigned int i2c_get_bus_num (void) +{ +	return bus_num; +} + +#endif	/* CONFIG_HARD_I2C */ diff --git a/arch/powerpc/cpu/mpc512x/ide.c b/arch/powerpc/cpu/mpc512x/ide.c new file mode 100644 index 000000000..dd6b2f467 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/ide.c @@ -0,0 +1,128 @@ +/* + * (C) Copyright 2007-2009 DENX Software Engineering + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> +#include <command.h> +#include <asm/io.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_IDE_RESET) + +void ide_set_reset (int idereset) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	debug ("ide_set_reset(%d)\n", idereset); + +	if (idereset) { +		out_be32(&im->pata.pata_ata_control, 0); +	} else { +		out_be32(&im->pata.pata_ata_control, FSL_ATA_CTRL_ATA_RST_B); +	} +	udelay(100); +} + +void init_ide_reset (void) +{ +	debug ("init_ide_reset\n"); + +	/* +	 * Clear the reset bit to reset the interface +	 * cf. RefMan MPC5121EE: 28.4.1 Resetting the ATA Bus +	 */ +	ide_set_reset(1); + +	/* Assert the reset bit to enable the interface */ +	ide_set_reset(0); + +} + +#define CALC_TIMING(t) (t + period - 1) / period + +int ide_preinit (void) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	long t; +	const struct { +		short t0; +		short t1; +		short t2_8; +		short t2_16; +		short t2i; +		short t4; +		short t9; +		short tA; +	} pio_specs = { +		.t0    = 600, +		.t1    =  70, +		.t2_8  = 290, +		.t2_16 = 165, +		.t2i   =   0, +		.t4    =  30, +		.t9    =  20, +		.tA    =  50, +	}; +	union { +		u32 config; +		struct { +			u8 field1; +			u8 field2; +			u8 field3; +			u8 field4; +		}bytes; +	} cfg; + +	debug ("IDE preinit using PATA peripheral at IMMR-ADDR %08x\n", +		(u32)&im->pata); + +	/* Set the reset bit to 1 to enable the interface */ +	ide_set_reset(0); + +	/* Init timings : we use PIO mode 0 timings */ +	t = 1000000000 / gd->ips_clk;	/* period in ns */ +	cfg.bytes.field1 = 3; +	cfg.bytes.field2 = 3; +	cfg.bytes.field3 = (pio_specs.t1 + t) / t; +	cfg.bytes.field4 = (pio_specs.t2_8 + t) / t; + +	out_be32(&im->pata.pata_time1, cfg.config); + +	cfg.bytes.field1 = (pio_specs.t2_8 + t) / t; +	cfg.bytes.field2 = (pio_specs.tA + t) / t + 2; +	cfg.bytes.field3 = 1; +	cfg.bytes.field4 = (pio_specs.t4 + t) / t; + +	out_be32(&im->pata.pata_time2, cfg.config); + +	cfg.config = in_be32(&im->pata.pata_time3); +	cfg.bytes.field1 = (pio_specs.t9 + t) / t; + +	out_be32(&im->pata.pata_time3, cfg.config); + +	debug ("PATA preinit complete.\n"); + +	return 0; +} + +#endif /* defined(CONFIG_IDE_RESET) */ diff --git a/arch/powerpc/cpu/mpc512x/iim.c b/arch/powerpc/cpu/mpc512x/iim.c new file mode 100644 index 000000000..8f2eb37e1 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/iim.c @@ -0,0 +1,394 @@ +/* + * Copyright 2008 Silicon Turnkey Express, Inc. + * Martha Marx <mmarx@silicontkx.com> + * + * ADS5121 IIM (Fusebox) Interface + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <asm/io.h> + +#ifdef CONFIG_CMD_FUSE + +DECLARE_GLOBAL_DATA_PTR; + +static char cur_bank = '1'; + +char *iim_err_msg(u32 err) +{ +	static char *IIM_errs[] = { +		"Parity Error in cache", +		"Explicit Sense Cycle Error", +		"Write to Locked Register Error", +		"Read Protect Error", +		"Override Protect Error", +		"Write Protect Error"}; + +	int i; + +	if (!err) +		return ""; +	for (i = 1; i < 8; i++) +		if (err & (1 << i)) +			printf("IIM - %s\n", IIM_errs[i-1]); +	return ""; +} + +int in_range(int n, int min, int max, char *err, char *usg) +{ +	if (n > max || n < min) { +		printf(err); +		printf("Usage:\n%s\n", usg); +		return 0; +	} +	return 1; +} + +int ads5121_fuse_read(int bank, int fstart, int num) +{ +	iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim; +	u32 *iim_fb, dummy; +	int f, ctr; + +	out_be32(&iim->err, in_be32(&iim->err)); +	if (bank == 0) +		iim_fb = (u32 *)&(iim->fbac0); +	else +		iim_fb = (u32 *)&(iim->fbac1); +/* try a read to see if Read Protect is set */ +	dummy = in_be32(&iim_fb[0]); +	if (in_be32(&iim->err) & IIM_ERR_RPE) { +		printf("\tRead protect fuse is set\n"); +		out_be32(&iim->err, IIM_ERR_RPE); +		return 0; +	} +	printf("Reading Bank %d cache\n", bank); +	for (f = fstart, ctr = 0; num > 0; ctr++, num--, f++) { +		if (ctr % 4 == 0) +			printf("F%2d:", f); +		printf("\t%#04x", (u8)(iim_fb[f])); +		if (ctr % 4 == 3) +			printf("\n"); +	} +	if (ctr % 4 != 0) +		printf("\n"); +} + +int ads5121_fuse_override(int bank, int f, u8 val) +{ +	iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim; +	u32 *iim_fb; +	u32 iim_stat; +	int i; + +	out_be32(&iim->err, in_be32(&iim->err)); +	if (bank == 0) +		iim_fb = (u32 *)&(iim->fbac0); +	else +		iim_fb = (u32 *)&(iim->fbac1); +/* try a read to see if Read Protect is set */ +	iim_stat = in_be32(&iim_fb[0]); +	if (in_be32(&iim->err) & IIM_ERR_RPE) { +		printf("Read protect fuse is set on bank %d;" +			"Override protect may also be set\n", bank); +		printf("An attempt will be made to override\n"); +		out_be32(&iim->err, IIM_ERR_RPE); +	} +	if (iim_stat & IIM_FBAC_FBOP) { +		printf("Override protect fuse is set on bank %d\n", bank); +		return 1; +	} +	if (f > IIM_FMAX) /* reset the entire bank */ +		for (i = 0; i < IIM_FMAX + 1; i++) +			out_be32(&iim_fb[i],  0); +	else +		out_be32(&iim_fb[f], val); +	return 0; +} + +int ads5121_fuse_prog(cmd_tbl_t *cmdtp, int bank, char *fuseno_bitno) +{ +	iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim; +	int f, i, bitno; +	u32 stat, err; + +	f = simple_strtol(fuseno_bitno, NULL, 10); +	if (f == 0 && fuseno_bitno[0] != '0') +		f = -1; +	if (!in_range(f, 0, IIM_FMAX, +		"<frow> must be between 0-31\n\n", cmdtp->usage)) +		return 1; +	bitno = -1; +	for (i = 0; i < 6; i++) { +		if (fuseno_bitno[i] == '_') { +			bitno = simple_strtol(&(fuseno_bitno[i+1]), NULL, 10); +			if (bitno == 0 && fuseno_bitno[i+1] != '0') +				bitno = -1; +			break; +		} +	} +	if (!in_range(bitno, 0, 7, "Bit number ranges from 0-7\n" +		"Example of <frow_bitno>: \"18_4\" sets bit 4 of row 18\n", +		cmdtp->usage)) +		return 1; +	out_be32(&iim->err, in_be32(&iim->err)); +	out_be32(&iim->prg_p, IIM_PRG_P_SET); +	out_be32(&iim->ua, IIM_SET_UA(bank, f)); +	out_be32(&iim->la, IIM_SET_LA(f, bitno)); +#ifdef DEBUG +	printf("Programming disabled with DEBUG defined \n"); +	printf(""Set up to pro +	printf("iim.ua = %x; iim.la = %x\n", iim->ua, iim->la); +#else +	out_be32(&iim->fctl, IIM_FCTL_PROG_PULSE | IIM_FCTL_PROG); +	do +		udelay(20); +	while ((stat = in_be32(&iim->stat)) & IIM_STAT_BUSY); +	out_be32(&iim->prg_p, 0); +	err = in_be32(&iim->err); +	if (stat & IIM_STAT_PRGD) { +		if (!(err & (IIM_ERR_WPE | IIM_ERR_WPE))) { +			printf("Fuse is successfully set"); +			if (err) +				printf(" - however there are other errors"); +			printf("\n"); +		} +		iim->stat = 0; +	} +	if (err) { +		iim_err_msg(err); +		out_be32(&iim->err, in_be32(&iim->err)); +	} +#endif +} + +int ads5121_fuse_sense(int bank, int fstart, int num) +{ +	iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim; +	u32 iim_fbac; +	u32 stat, err, err_hold = 0; +	int f, ctr; + +	out_be32(&iim->err, in_be32(&iim->err)); +	if (bank == 0) +		iim_fbac = in_be32(&iim->fbac0); +	else +		iim_fbac = in_be32(&iim->fbac1); +	if (iim_fbac & IIM_FBAC_FBESP) { +		printf("\tSense Protect disallows this operation\n"); +		out_be32(&iim->err, IIM_FBAC_FBESP); +		return 1; +	} +	err = in_be32(&iim->err); +	if (err) { +		iim_err_msg(err); +		err_hold |= err; +	} +	if (err & IIM_ERR_RPE) +		printf("\tRead protect fuse is set; " +			"Sense Protect may be set but will be attempted\n"); +	if (err) +		out_be32(&iim->err, err); +	printf("Sensing fuse(s) on Bank %d\n", bank); +	for (f = fstart, ctr = 0; num > 0; ctr++, f++, num--) { +		out_be32(&iim->ua, IIM_SET_UA(bank, f)); +		out_be32(&iim->la, IIM_SET_LA(f, 0)); +		out_be32(&iim->fctl,  IIM_FCTL_ESNS_N); +		do +			udelay(20); +		while ((stat = in_be32(&iim->stat)) & IIM_STAT_BUSY); +		err = in_be32(&iim->err); +		if (err & IIM_ERR_SNSE) { +			iim_err_msg(err); +			out_be32(&iim->err, IIM_ERR_SNSE); +			return 1; +		} +		if (stat & IIM_STAT_SNSD) { +			out_be32(&iim->stat, 0); +			if (ctr % 4 == 0) +				printf("F%2d:", f); +			printf("\t%#04x", (u8)iim->sdat); +			if (ctr % 4 == 3) +				printf("\n"); +		} +		if (err) { +			err_hold |= err; +			out_be32(&iim->err, err); +		} +	} +	if (ctr % 4 != 0) +		printf("\n"); +	if (err_hold) +		iim_err_msg(err_hold); + +	return 0; +} + +int ads5121_fuse_stat(int bank) +{ +	iim512x_t *iim = &((immap_t *) CONFIG_SYS_IMMR)->iim; +	u32 iim_fbac; +	u32 err; + +	out_be32(&iim->err, in_be32(&iim->err)); +	if (bank == 0) +		iim_fbac = in_be32(&iim->fbac0); +	else +		iim_fbac = in_be32(&iim->fbac1); +	err = in_be32(&iim->err); +	if (err) +		iim_err_msg(err); +	if (err & IIM_ERR_RPE  || iim_fbac & IIM_FBAC_FBRP) { +		if (iim_fbac == 0) +			printf("Since protection settings can't be read - " +				"try sensing fuse row 0;\n"); +		return 0; +	} +	if (iim_fbac & IIM_PROTECTION) +		printf("Protection Fuses Bank %d = %#04x:\n", bank, iim_fbac); +	else if (!(err & IIM_ERR_RPE)) +		printf("No Protection fuses are set\n"); +	if (iim_fbac & IIM_FBAC_FBWP) +		printf("\tWrite Protect fuse is set\n"); +	if (iim_fbac & IIM_FBAC_FBOP) +		printf("\tOverride Protect fuse is set\n"); +	if (iim_fbac & IIM_FBAC_FBESP) +		printf("\tSense Protect Fuse is set\n"); +	out_be32(&iim->err, in_be32(&iim->err)); + +	return 0; +} + +int do_ads5121_fuse(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	int frow, n, v, bank; + +	if (cur_bank == '0') +		bank = 0; +	else +		bank = 1; + +	switch (argc) { +	case 0: +	case 1: +		printf("Usage:\n%s\n", cmdtp->usage); +		return 1; +	case 2: +		if (strncmp(argv[1], "stat", 4) == 0) +			return ads5121_fuse_stat(bank); +		if (strncmp(argv[1], "read", 4) == 0) +			return ads5121_fuse_read(bank, 0, IIM_FMAX + 1); +		if (strncmp(argv[1], "sense", 5) == 0) +			return ads5121_fuse_sense(bank, 0, IIM_FMAX + 1); +		if (strncmp(argv[1], "ovride", 6) == 0) +			return ads5121_fuse_override(bank, IIM_FMAX + 1, 0); +		if (strncmp(argv[1], "bank", 4) == 0) { +			printf("Active Fuse Bank is %c\n", cur_bank); +			return 0; +		} +		printf("Usage:\n%s\n", cmdtp->usage); +		return 1; +	case 3: +		if (strncmp(argv[1], "bank", 4) == 0) { +			if (argv[2][0] == '0') +				cur_bank = '0'; +			else if (argv[2][0] == '1') +				cur_bank = '1'; +			else { +				printf("Usage:\n%s\n", cmdtp->usage); +				return 1; +			} + +			printf("Setting Active Fuse Bank to %c\n", cur_bank); +			return 0; +		} +		if (strncmp(argv[1], "prog", 4) == 0) +			return ads5121_fuse_prog(cmdtp, bank, argv[2]); + +		frow = (int)simple_strtol(argv[2], NULL, 10); +		if (frow == 0 && argv[2][0] != '0') +			frow = -1; +		if (!in_range(frow, 0, IIM_FMAX, +			"<frow> must be between 0-31\n\n", cmdtp->usage)) +			return 1; +		if (strncmp(argv[1], "read", 4) == 0) +			return ads5121_fuse_read(bank, frow, 1); +		if (strncmp(argv[1], "ovride", 6) == 0) +			return ads5121_fuse_override(bank, frow, 0); +		if (strncmp(argv[1], "sense", 5) == 0) +			return ads5121_fuse_sense(bank, frow, 1); +		printf("Usage:\n%s\n", cmdtp->usage); +		return 1; +	case 4: +		frow = (int)simple_strtol(argv[2], NULL, 10); +		if (frow == 0 && argv[2][0] != '0') +			frow = -1; +		if (!in_range(frow, 0, IIM_FMAX, +			"<frow> must be between 0-31\n\n", cmdtp->usage)) +			return 1; +		if (strncmp(argv[1], "read", 4) == 0) { +			n = (int)simple_strtol(argv[3], NULL, 10); +			if (!in_range(frow + n, frow + 1, IIM_FMAX + 1, +				"<frow>+<n> must be between 1-32\n\n", +				cmdtp->usage)) +				return 1; +			return ads5121_fuse_read(bank, frow, n); +		} +		if (strncmp(argv[1], "ovride", 6) == 0) { +			v = (int)simple_strtol(argv[3], NULL, 10); +			return ads5121_fuse_override(bank, frow, v); +		} +		if (strncmp(argv[1], "sense", 5) == 0) { +			n = (int)simple_strtol(argv[3], NULL, 10); +			if (!in_range(frow + n, frow + 1, IIM_FMAX + 1, +				"<frow>+<n> must be between 1-32\n\n", +				cmdtp->usage)) +				return 1; +			return ads5121_fuse_sense(bank, frow, n); +		} +		printf("Usage:\n%s\n", cmdtp->usage); +		return 1; +	default: /* at least 5 args */ +		printf("Usage:\n%s\n", cmdtp->usage); +		return 1; +	} +} + +U_BOOT_CMD( +	fuse, CONFIG_SYS_MAXARGS, 0, do_ads5121_fuse, +	"   - Read, Sense, Override or Program Fuses\n", +	"bank <n>		- sets active Fuse Bank to 0 or 1\n" +	"			    no args shows current active bank\n" +	"fuse stat		- print active fuse bank's protection status\n" +	"fuse read [<frow> [<n>]] - print <n> fuse rows starting at <frow>\n" +	"			    no args to print entire bank's fuses\n" +	"fuse ovride [<frow> [<v>]]- override fuses at <frow> with <v>\n" +	"			    no <v> defaults to 0 for the row\n" +	"			    no args resets entire bank to 0\n" +	"			  NOTE - settings persist until hard reset\n" +	"fuse sense [<frow>]	- senses current fuse at <frow>\n" +	"			    no args for entire bank\n" +	"fuse prog <frow_bit> 	- program fuse at row <frow>, bit <_bit>\n" +	"			    <frow> is 0-31, <bit> is 0-7; eg. 13_2 \n" +	"			  WARNING - this is permanent" +); +#endif /* CONFIG_CMD_FUSE */ diff --git a/arch/powerpc/cpu/mpc512x/interrupts.c b/arch/powerpc/cpu/mpc512x/interrupts.c new file mode 100644 index 000000000..ef7c773b2 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/interrupts.c @@ -0,0 +1,61 @@ +/* + * (C) Copyright 2000-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright 2004 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 + * + * Derived from the MPC83xx code. + */ + +#include <common.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct irq_action { +	interrupt_handler_t *handler; +	void *arg; +	ulong count; +}; + +int interrupt_init_cpu (unsigned *decrementer_count) +{ +	*decrementer_count = get_tbclk () / CONFIG_SYS_HZ; + +	return 0; +} + +/* + * Install and free an interrupt handler. + */ +void +irq_install_handler (int irq, interrupt_handler_t * handler, void *arg) +{ +} + +void irq_free_handler (int irq) +{ +} + +void timer_interrupt_cpu (struct pt_regs *regs) +{ +	/* nothing to do here */ +	return; +} diff --git a/arch/powerpc/cpu/mpc512x/iopin.c b/arch/powerpc/cpu/mpc512x/iopin.c new file mode 100644 index 000000000..be2094762 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/iopin.c @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2008 + * Martha J Marx, Silicon Turnkey Express, mmarx@silicontkx.com + * mpc512x I/O pin/pad initialization for the ADS5121 board + * 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 <linux/types.h> +#include <asm/io.h> + +void iopin_initialize(iopin_t *ioregs_init, int len) +{ +	short i, j, p; +	u32 *reg; +	immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + +	reg = (u32 *)&(im->io_ctrl); + +	if (sizeof(ioregs_init) == 0) +		return; + +	for (i = 0; i < len; i++) { +		for (p = 0, j = ioregs_init[i].p_offset / sizeof(u_long); +			p < ioregs_init[i].nr_pins; p++, j++) { +			if (ioregs_init[i].bit_or) +				setbits_be32(reg + j, ioregs_init[i].val); +			else +				out_be32 (reg + j, ioregs_init[i].val); +		} +	} +	return; +} diff --git a/arch/powerpc/cpu/mpc512x/pci.c b/arch/powerpc/cpu/mpc512x/pci.c new file mode 100644 index 000000000..141db8b86 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/pci.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2009-2010 DENX Software Engineering <wd@denx.de> + * Copyright (C) Freescale Semiconductor, Inc. 2006, 2007. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +#include <asm/io.h> +#include <asm/mmu.h> +#include <asm/global_data.h> +#include <pci.h> +#if defined(CONFIG_OF_LIBFDT) +#include <libfdt.h> +#include <fdt_support.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +/* System RAM mapped to PCI space */ +#define CONFIG_PCI_SYS_MEM_BUS	CONFIG_SYS_SDRAM_BASE +#define CONFIG_PCI_SYS_MEM_PHYS	CONFIG_SYS_SDRAM_BASE + +static struct pci_controller pci_hose; + + +/************************************************************************** + * pci_init_board() + * + */ +void +pci_init_board(void) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile law512x_t *pci_law; +	volatile pot512x_t *pci_pot; +	volatile pcictrl512x_t *pci_ctrl; +	volatile pciconf512x_t *pci_conf; +	u16 reg16; +	u32 reg32; +	u32 dev; +	int i; +	struct pci_controller *hose; + +	/* Set PCI divider for 33MHz */ +	reg32 = in_be32(&im->clk.scfr[0]); +	reg32 &= ~(SCFR1_PCI_DIV_MASK); +	reg32 |= SCFR1_PCI_DIV << SCFR1_PCI_DIV_SHIFT; +	out_be32(&im->clk.scfr[0], reg32); + +	clrsetbits_be32(&im->clk.scfr[0], +			SCFR1_PCI_DIV_MASK, +			SCFR1_PCI_DIV << SCFR1_PCI_DIV_SHIFT +	); + +	pci_law = im->sysconf.pcilaw; +	pci_pot = im->ios.pot; +	pci_ctrl = &im->pci_ctrl; +	pci_conf = &im->pci_conf; + +	hose = &pci_hose; + +	/* +	 * Release PCI RST Output signal +	 */ +	out_be32(&pci_ctrl->gcr, 0); +	udelay(2000); +	out_be32(&pci_ctrl->gcr, 1); + +	/* We need to wait at least a 1sec based on PCI specs */ +	for (i = 0; i < 1000; i++) +		udelay(1000); + +	/* +	 * Configure PCI Local Access Windows +	 */ +	out_be32(&pci_law[0].bar, CONFIG_SYS_PCI_MEM_PHYS & LAWBAR_BAR); +	out_be32(&pci_law[0].ar, LAWAR_EN | LAWAR_SIZE_512M); + +	out_be32(&pci_law[1].bar, CONFIG_SYS_PCI_IO_PHYS & LAWBAR_BAR); +	out_be32(&pci_law[1].ar, LAWAR_EN | LAWAR_SIZE_16M); + +	/* +	 * Configure PCI Outbound Translation Windows +	 */ + +	/* PCI mem space - prefetch */ +	out_be32(&pci_pot[0].potar, +		(CONFIG_SYS_PCI_MEM_BASE >> 12) & POTAR_TA_MASK); +	out_be32(&pci_pot[0].pobar, +		(CONFIG_SYS_PCI_MEM_PHYS >> 12) & POBAR_BA_MASK); +	out_be32(&pci_pot[0].pocmr, +		POCMR_EN | POCMR_PRE | POCMR_CM_256M); + +	/* PCI IO space */ +	out_be32(&pci_pot[1].potar, +		(CONFIG_SYS_PCI_IO_BASE >> 12) & POTAR_TA_MASK); +	out_be32(&pci_pot[1].pobar, +		(CONFIG_SYS_PCI_IO_PHYS >> 12) & POBAR_BA_MASK); +	out_be32(&pci_pot[1].pocmr, +		POCMR_EN | POCMR_IO | POCMR_CM_16M); + +	/* PCI mmio - non-prefetch mem space */ +	out_be32(&pci_pot[2].potar, +		(CONFIG_SYS_PCI_MMIO_BASE >> 12) & POTAR_TA_MASK); +	out_be32(&pci_pot[2].pobar, +		(CONFIG_SYS_PCI_MMIO_PHYS >> 12) & POBAR_BA_MASK); +	out_be32(&pci_pot[2].pocmr, +		POCMR_EN | POCMR_CM_256M); + +	/* +	 * Configure PCI Inbound Translation Windows +	 */ + +	/* we need RAM mapped to PCI space for the devices to +	 * access main memory */ +	out_be32(&pci_ctrl[0].pitar1, 0x0); +	out_be32(&pci_ctrl[0].pibar1, 0x0); +	out_be32(&pci_ctrl[0].piebar1, 0x0); +	out_be32(&pci_ctrl[0].piwar1, +		PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP | +		PIWAR_WTT_SNOOP | (__ilog2(gd->ram_size) - 1)); + +	hose->first_busno = 0; +	hose->last_busno = 0xff; + +	/* PCI memory prefetch space */ +	pci_set_region(hose->regions + 0, +		       CONFIG_SYS_PCI_MEM_BASE, +		       CONFIG_SYS_PCI_MEM_PHYS, +		       CONFIG_SYS_PCI_MEM_SIZE, +		       PCI_REGION_MEM|PCI_REGION_PREFETCH); + +	/* PCI memory space */ +	pci_set_region(hose->regions + 1, +		       CONFIG_SYS_PCI_MMIO_BASE, +		       CONFIG_SYS_PCI_MMIO_PHYS, +		       CONFIG_SYS_PCI_MMIO_SIZE, +		       PCI_REGION_MEM); + +	/* PCI IO space */ +	pci_set_region(hose->regions + 2, +		       CONFIG_SYS_PCI_IO_BASE, +		       CONFIG_SYS_PCI_IO_PHYS, +		       CONFIG_SYS_PCI_IO_SIZE, +		       PCI_REGION_IO); + +	/* System memory space */ +	pci_set_region(hose->regions + 3, +		       CONFIG_PCI_SYS_MEM_BUS, +		       CONFIG_PCI_SYS_MEM_PHYS, +		       gd->ram_size, +		       PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); + +	hose->region_count = 4; + +	pci_setup_indirect(hose, +			   (CONFIG_SYS_IMMR + 0x8300), +			   (CONFIG_SYS_IMMR + 0x8304)); + +	pci_register_hose(hose); + +	/* +	 * Write to Command register +	 */ +	reg16 = 0xff; +	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); +	pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80); +	pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08); + +#ifdef CONFIG_PCI_SCAN_SHOW +	printf("PCI:   Bus Dev VenId DevId Class Int\n"); +#endif +	/* +	 * Hose scan. +	 */ +	hose->last_busno = pci_hose_scan(hose); +} + +#if defined(CONFIG_OF_LIBFDT) +void ft_pci_setup(void *blob, bd_t *bd) +{ +	int nodeoffset; +	int tmp[2]; +	const char *path; + +	nodeoffset = fdt_path_offset(blob, "/aliases"); +	if (nodeoffset >= 0) { +		path = fdt_getprop(blob, nodeoffset, "pci", NULL); +		if (path) { +			tmp[0] = cpu_to_be32(pci_hose.first_busno); +			tmp[1] = cpu_to_be32(pci_hose.last_busno); +			do_fixup_by_path(blob, path, "bus-range", +				&tmp, sizeof(tmp), 1); + +			tmp[0] = cpu_to_be32(gd->pci_clk); +			do_fixup_by_path(blob, path, "clock-frequency", +				&tmp, sizeof(tmp[0]), 1); +		} +	} +} +#endif /* CONFIG_OF_LIBFDT */ diff --git a/arch/powerpc/cpu/mpc512x/serial.c b/arch/powerpc/cpu/mpc512x/serial.c new file mode 100644 index 000000000..ec2f41bb3 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/serial.c @@ -0,0 +1,193 @@ +/* + * (C) Copyright 2000 - 2010 + * 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 + * + * Based ont the MPC5200 PSC driver. + * Adapted for MPC512x by Jan Wrobel <wrr@semihalf.com> + */ + +/* + * Minimal serial functions needed to use one of the PSC ports + * as serial console interface. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_PSC_CONSOLE) + +static void fifo_init (volatile psc512x_t *psc) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; + +	/* reset Rx & Tx fifo slice */ +	out_be32(&psc->rfcmd, PSC_FIFO_RESET_SLICE); +	out_be32(&psc->tfcmd, PSC_FIFO_RESET_SLICE); + +	/* disable Tx & Rx FIFO interrupts */ +	out_be32(&psc->rfintmask, 0); +	out_be32(&psc->tfintmask, 0); + +	out_be32(&psc->tfsize, CONSOLE_FIFO_TX_SIZE | (CONSOLE_FIFO_TX_ADDR << 16)); +	out_be32(&psc->rfsize, CONSOLE_FIFO_RX_SIZE | (CONSOLE_FIFO_RX_ADDR << 16)); + +	/* enable Tx & Rx FIFO slice */ +	out_be32(&psc->rfcmd, PSC_FIFO_ENABLE_SLICE); +	out_be32(&psc->tfcmd, PSC_FIFO_ENABLE_SLICE); + +	out_be32(&im->fifoc.fifoc_cmd, FIFOC_DISABLE_CLOCK_GATE); +	__asm__ volatile ("sync"); +} + +void serial_setbrg(void) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; +	unsigned long baseclk, div; + +	/* calculate dividor for setting PSC CTUR and CTLR registers */ +	baseclk = (gd->ips_clk + 8) / 16; +	div = (baseclk + (gd->baudrate / 2)) / gd->baudrate; + +	out_8(&psc->ctur, (div >> 8) & 0xff); +	out_8(&psc->ctlr,  div & 0xff); /* set baudrate */ +} + +int serial_init(void) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + +	fifo_init (psc); + +	/* set MR register to point to MR1 */ +	out_8(&psc->command, PSC_SEL_MODE_REG_1); + +	/* disable Tx/Rx */ +	out_8(&psc->command, PSC_TX_DISABLE | PSC_RX_DISABLE); + +	/* choose the prescaler	by 16 for the Tx/Rx clock generation */ +	out_be16(&psc->psc_clock_select, 0xdd00); + +	/* switch to UART mode */ +	out_be32(&psc->sicr, 0); + +	/* mode register points to mr1 */ +	/* configure parity, bit length and so on in mode register 1*/ +	out_8(&psc->mode, PSC_MODE_8_BITS | PSC_MODE_PARNONE); +	/* now, mode register points to mr2 */ +	out_8(&psc->mode, PSC_MODE_1_STOPBIT); + +	/* set baudrate */ +	serial_setbrg(); + +	/* disable all interrupts */ +	out_be16(&psc->psc_imr, 0); + +	/* reset and enable Rx/Tx */ +	out_8(&psc->command, PSC_RST_RX); +	out_8(&psc->command, PSC_RST_TX); +	out_8(&psc->command, PSC_RX_ENABLE | PSC_TX_ENABLE); + +	return 0; +} + +void serial_putc (const char c) +{ +	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; +	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + +	if (c == '\n') +		serial_putc ('\r'); + +	/* Wait for last character to go. */ +	while (!(in_be16(&psc->psc_status) & PSC_SR_TXEMP)) +		; + +	out_8(&psc->tfdata_8, c); +} + +void serial_putc_raw (const char c) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + +	/* Wait for last character to go. */ +	while (!(in_be16(&psc->psc_status) & PSC_SR_TXEMP)) +		; + +	out_8(&psc->tfdata_8, c); +} + + +void serial_puts (const char *s) +{ +	while (*s) { +		serial_putc (*s++); +	} +} + +int serial_getc (void) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + +	/* Wait for a character to arrive. */ +	while (in_be32(&psc->rfstat) & PSC_FIFO_EMPTY) +		; + +	return in_8(&psc->rfdata_8); +} + +int serial_tstc (void) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + +	return !(in_be32(&psc->rfstat) & PSC_FIFO_EMPTY); +} + +void serial_setrts(int s) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + +	if (s) { +		/* Assert RTS (become LOW) */ +		out_8(&psc->op1, 0x1); +	} +	else { +		/* Negate RTS (become HIGH) */ +		out_8(&psc->op0, 0x1); +	} +} + +int serial_getcts(void) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + +	return (in_8(&psc->ip) & 0x1) ? 0 : 1; +} +#endif /* CONFIG_PSC_CONSOLE */ diff --git a/arch/powerpc/cpu/mpc512x/speed.c b/arch/powerpc/cpu/mpc512x/speed.c new file mode 100644 index 000000000..ce8d0949b --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/speed.c @@ -0,0 +1,156 @@ +/* + * (C) Copyright 2000-2009 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 2004-2006 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 + * + * Based on the MPC83xx code. + */ + +#include <common.h> +#include <command.h> +#include <asm/io.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int spmf_mult[] = { +	68, 1, 12, 16, +	20, 24, 28, 32, +	36, 40, 44, 48, +	52, 56, 60, 64 +}; + +static int cpmf_mult[][2] = { +	{0, 1}, {0, 1}, /* 0 and 1 are not valid */ +	{1, 1}, {3, 2}, +	{2, 1}, {5, 2}, +	{3, 1}, {7, 2}, +	{0, 1}, {0, 1}, /* and all above 7 are not valid too */ +	{0, 1}, {0, 1}, +	{0, 1}, {0, 1}, +	{0, 1}, {0, 1} +}; + +static int sys_dividors[][2] = { +	{2, 1}, {5, 2}, {3, 1}, {7, 2}, {4, 1}, +	{9, 2}, {5, 1}, {7, 1}, {6, 1}, {8, 1}, +	{9, 1}, {11, 1}, {10, 1}, {12, 1}, {13, 1}, +	{15, 1}, {14, 1}, {16, 1}, {17, 1}, {19, 1}, +	{18, 1}, {20, 1}, {21, 1}, {23, 1}, {22, 1}, +	{24, 1}, {25, 1}, {27, 1}, {26, 1}, {28, 1}, +	{29, 1}, {31, 1}, {30, 1}, {32, 1}, {33, 1} +}; + +int get_clocks (void) +{ +	volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; +	u8 spmf; +	u8 cpmf; +	u8 sys_div; +	u8 ips_div; +	u8 pci_div; +	u32 ref_clk = CONFIG_SYS_MPC512X_CLKIN; +	u32 spll; +	u32 sys_clk; +	u32 core_clk; +	u32 csb_clk; +	u32 ips_clk; +	u32 pci_clk; +	u32 reg; + +	reg = in_be32(&im->sysconf.immrbar); +	if ((reg & IMMRBAR_BASE_ADDR) != (u32) im) +		return -1; + +	reg = in_be32(&im->clk.spmr); +	spmf = (reg & SPMR_SPMF) >> SPMR_SPMF_SHIFT; +	spll = ref_clk * spmf_mult[spmf]; + +	reg = in_be32(&im->clk.scfr[1]); +	sys_div = (reg & SCFR2_SYS_DIV) >> SCFR2_SYS_DIV_SHIFT; +	sys_clk = (spll * sys_dividors[sys_div][1]) / sys_dividors[sys_div][0]; + +	csb_clk = sys_clk / 2; + +	reg = in_be32(&im->clk.spmr); +	cpmf = (reg & SPMR_CPMF) >> SPMR_CPMF_SHIFT; +	core_clk = (csb_clk * cpmf_mult[cpmf][0]) / cpmf_mult[cpmf][1]; + +	reg = in_be32(&im->clk.scfr[0]); +	ips_div = (reg & SCFR1_IPS_DIV_MASK) >> SCFR1_IPS_DIV_SHIFT; +	if (ips_div != 0) { +		ips_clk = csb_clk / ips_div; +	} else { +		/* in case we cannot get a sane IPS divisor, fail gracefully */ +		ips_clk = 0; +	} + +	reg = in_be32(&im->clk.scfr[0]); +	pci_div = (reg & SCFR1_PCI_DIV_MASK) >> SCFR1_PCI_DIV_SHIFT; +	if (pci_div != 0) { +		pci_clk = csb_clk / pci_div; +	} else { +		/* in case we cannot get a sane IPS divisor, fail gracefully */ +		pci_clk = 333333; +	} + +	gd->ips_clk = ips_clk; +	gd->pci_clk = pci_clk; +	gd->csb_clk = csb_clk; +	gd->cpu_clk = core_clk; +	gd->bus_clk = csb_clk; +	return 0; + +} + +/******************************************** + * get_bus_freq + * return system bus freq in Hz + *********************************************/ +ulong get_bus_freq (ulong dummy) +{ +	return gd->csb_clk; +} + +int do_clocks (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ +	char buf[32]; + +	printf("Clock configuration:\n"); +	printf("  CPU:                 %-4s MHz\n", strmhz(buf, gd->cpu_clk)); +	printf("  Coherent System Bus: %-4s MHz\n", strmhz(buf, gd->csb_clk)); +	printf("  IPS Bus:             %-4s MHz\n", strmhz(buf, gd->ips_clk)); +	printf("  PCI:                 %-4s MHz\n", strmhz(buf, gd->pci_clk)); +	printf("  DDR:                 %-4s MHz\n", strmhz(buf, 2*gd->csb_clk)); +	return 0; +} + +U_BOOT_CMD(clocks, 1, 0, do_clocks, +	"print clock configuration", +	"    clocks" +); + +int prt_mpc512x_clks (void) +{ +	do_clocks (NULL, 0, 0, NULL); +	return (0); +} diff --git a/arch/powerpc/cpu/mpc512x/start.S b/arch/powerpc/cpu/mpc512x/start.S new file mode 100644 index 000000000..d26b61707 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/start.S @@ -0,0 +1,711 @@ +/* + * Copyright (C) 1998  Dan Malek <dmalek@jlc.net> + * Copyright (C) 1999  Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se> + * Copyright (C) 2000-2009 Wolfgang Denk <wd@denx.de> + * Copyright Freescale Semiconductor, Inc. 2004, 2006. + * + * 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 + * + * Based on the MPC83xx code. + */ + +/* + *  U-Boot - Startup Code for MPC512x based Embedded Boards + */ + +#include <config.h> +#include <timestamp.h> +#include <version.h> + +#define CONFIG_521X	1		/* needed for Linux kernel header files*/ + +#include <asm/immap_512x.h> +#include "asm-offsets.h" + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +#include <asm/cache.h> +#include <asm/mmu.h> + +#ifndef  CONFIG_IDENT_STRING +#define  CONFIG_IDENT_STRING "MPC512X" +#endif + +/* + * Floating Point enable, Machine Check and Recoverable Interr. + */ +#undef	MSR_KERNEL +#ifdef DEBUG +#define MSR_KERNEL (MSR_FP|MSR_RI) +#else +#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI) +#endif + +/* Macros for manipulating CSx_START/STOP */ +#define START_REG(start)	((start) >> 16) +#define STOP_REG(start, size)	(((start) + (size) - 1) >> 16) + +/* + * Set up GOT: Global Offset Table + * + * Use r12 to access the GOT + */ +	START_GOT +	GOT_ENTRY(_GOT2_TABLE_) +	GOT_ENTRY(_FIXUP_TABLE_) + +	GOT_ENTRY(_start) +	GOT_ENTRY(_start_of_vectors) +	GOT_ENTRY(_end_of_vectors) +	GOT_ENTRY(transfer_to_handler) + +	GOT_ENTRY(__init_end) +	GOT_ENTRY(_end) +	GOT_ENTRY(__bss_start) +	END_GOT + +/* + * Magic number and version string + */ +	.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" + +/* + * Vector Table + */ +	.text +	. = EXC_OFF_SYS_RESET + +	.globl	_start +	/* Start from here after reset/power on */ +_start: +	li	r21, BOOTFLAG_COLD  /* Normal Power-On: Boot from FLASH */ +	b	boot_cold + +	.globl	_start_of_vectors +_start_of_vectors: + +/* Machine check */ +	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) + +/* Data Storage exception. */ +	STD_EXCEPTION(0x300, DataStorage, UnknownException) + +/* Instruction Storage exception. */ +	STD_EXCEPTION(0x400, InstStorage, UnknownException) + +/* External Interrupt exception. */ +	STD_EXCEPTION(0x500, ExtInterrupt, UnknownException) + +/* Alignment exception. */ +	. = 0x600 +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 */ +	. = 0x700 +ProgramCheck: +	EXCEPTION_PROLOG(SRR0, SRR1) +	addi	r3,r1,STACK_FRAME_OVERHEAD +	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException, +		MSR_KERNEL, COPY_EE) + +/* Floating Point Unit unavailable exception */ +	STD_EXCEPTION(0x800, FPUnavailable, UnknownException) + +/* Decrementer */ +	STD_EXCEPTION(0x900, Decrementer, timer_interrupt) + +/* Critical interrupt */ +	STD_EXCEPTION(0xa00, Critical, UnknownException) + +/* System Call */ +	STD_EXCEPTION(0xc00, SystemCall, UnknownException) + +/* Trace interrupt */ +	STD_EXCEPTION(0xd00, Trace, UnknownException) + +/* Performance Monitor interrupt */ +	STD_EXCEPTION(0xf00, PerfMon, UnknownException) + +/* Intruction Translation Miss */ +	STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException) + +/* Data Load Translation Miss */ +	STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException) + +/* Data Store Translation Miss */ +	STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException) + +/* Instruction Address Breakpoint */ +	STD_EXCEPTION(0x1300, InstructionAddrBreakpoint, DebugException) + +/* System Management interrupt */ +	STD_EXCEPTION(0x1400, SystemMgmtInterrupt, UnknownException) + +	.globl	_end_of_vectors +_end_of_vectors: + +	. = 0x3000 +boot_cold: +	/* Save msr contents */ +	mfmsr	r5 + +	/* Set IMMR area to our preferred location */ +	lis	r4, CONFIG_DEFAULT_IMMR@h +	lis	r3, CONFIG_SYS_IMMR@h +	ori	r3, r3, CONFIG_SYS_IMMR@l +	stw	r3, IMMRBAR(r4) +	mtspr	MBAR, r3		/* IMMRBAR is mirrored into the MBAR SPR (311) */ + +	/* Initialise the machine */ +	bl	cpu_early_init + +	/* +	 * Set up Local Access Windows: +	 * +	 * 1) Boot/CS0 (boot FLASH) +	 * 2) On-chip SRAM (initial stack purposes) +	 */ + +	/* Boot CS/CS0 window range */ +	lis     r3, CONFIG_SYS_IMMR@h +	ori     r3, r3, CONFIG_SYS_IMMR@l + +	lis	r4, START_REG(CONFIG_SYS_FLASH_BASE) +	ori	r4, r4, STOP_REG(CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_SIZE) +	stw	r4, LPCS0AW(r3) + +	/* +	 * The SRAM window has a fixed size (256K), so only the start address +	 * is necessary +	 */ +	lis	r4, START_REG(CONFIG_SYS_SRAM_BASE) & 0xff00 +	stw	r4, SRAMBAR(r3) + +	/* +	 * According to MPC5121e RM, configuring local access windows should +	 * be followed by a dummy read of the config register that was +	 * modified last and an isync +	 */ +	lwz	r4, SRAMBAR(r3) +	isync + +	/* +	 * Set configuration of the Boot/CS0, the SRAM window does not have a +	 * config register so no params can be set for it +	 */ +	lis     r3, (CONFIG_SYS_IMMR + LPC_OFFSET)@h +	ori     r3, r3, (CONFIG_SYS_IMMR + LPC_OFFSET)@l + +	lis     r4, CONFIG_SYS_CS0_CFG@h +	ori     r4, r4, CONFIG_SYS_CS0_CFG@l +	stw     r4, CS0_CONFIG(r3) + +	/* Master enable all CS's */ +	lis	r4, CS_CTRL_ME@h +	ori	r4, r4, CS_CTRL_ME@l +	stw	r4, CS_CTRL(r3) + +	lis	r4, (CONFIG_SYS_MONITOR_BASE)@h +	ori	r4, r4, (CONFIG_SYS_MONITOR_BASE)@l +	addi	r5, r4, in_flash - _start + EXC_OFF_SYS_RESET +	mtlr	r5 +	blr + +in_flash: +	lis	r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h +	ori	r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l + +	li	r0, 0		/* Make room for stack frame header and	*/ +	stwu	r0, -4(r1)	/* clear final stack frame so that	*/ +	stwu	r0, -4(r1)	/* stack backtraces terminate cleanly	*/ + +	/* let the C-code set up the rest			*/ +	/*							*/ +	/* Be careful to keep code relocatable & stack humble	*/ +	/*------------------------------------------------------*/ + +	GET_GOT			/* initialize GOT access	*/ + +	/* r3: IMMR */ +	lis	r3, CONFIG_SYS_IMMR@h +	/* run low-level CPU init code (in Flash) */ +	bl	cpu_init_f + +	/* r3: BOOTFLAG */ +	mr	r3, r21 +	/* run 1st part of board init code (in Flash) */ +	bl	board_init_f + +	/* NOTREACHED - board_init_f() does not return */ + +/* + * 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) +	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 + +/* + * This code initialises the machine, it expects original MSR contents to be in r5. + */ +cpu_early_init: +	/* Initialize machine status; enable machine check interrupt */ +	/*-----------------------------------------------------------*/ + +	li	r3, MSR_KERNEL			/* Set ME and RI flags */ +	rlwimi	r3, r5, 0, 25, 25		/* preserve IP bit */ +#ifdef DEBUG +	rlwimi	r3, r5, 0, 21, 22		/* debugger might set SE, BE bits */ +#endif +	mtmsr	r3 +	SYNC +	mtspr	SRR1, r3			/* Mirror current MSR state in SRR1 */ + +	lis	r3, CONFIG_SYS_IMMR@h + +#if defined(CONFIG_WATCHDOG) +	/* Initialise the watchdog and reset it */ +	/*--------------------------------------*/ +	lis r4, CONFIG_SYS_WATCHDOG_VALUE +	ori r4, r4, (SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR) +	stw r4, SWCRR(r3) + +	/* reset */ +	li	r4, 0x556C +	sth	r4, SWSRR@l(r3) +	li	r4, 0x0 +	ori	r4, r4, 0xAA39 +	sth	r4, SWSRR@l(r3) +#else +	/* Disable the watchdog */ +	/*----------------------*/ +	lwz r4, SWCRR(r3) +	/* +	 * Check to see if it's enabled for disabling: once disabled by s/w +	 * it's not possible to re-enable it +	 */ +	andi. r4, r4, 0x4 +	beq 1f +	xor r4, r4, r4 +	stw r4, SWCRR(r3) +1: +#endif /* CONFIG_WATCHDOG */ + +	/* Initialize the Hardware Implementation-dependent Registers */ +	/* HID0 also contains cache control			*/ +	/*------------------------------------------------------*/ +	lis	r3, CONFIG_SYS_HID0_INIT@h +	ori	r3, r3, CONFIG_SYS_HID0_INIT@l +	SYNC +	mtspr	HID0, r3 + +	lis	r3, CONFIG_SYS_HID0_FINAL@h +	ori	r3, r3, CONFIG_SYS_HID0_FINAL@l +	SYNC +	mtspr	HID0, r3 + +	lis	r3, CONFIG_SYS_HID2@h +	ori	r3, r3, CONFIG_SYS_HID2@l +	SYNC +	mtspr	HID2, r3 +	sync +	blr + + +/* Cache functions. + * + * Note: requires that all cache bits in + * HID0 are in the low half word. + */ +	.globl	icache_enable +icache_enable: +	mfspr	r3, HID0 +	ori	r3, r3, HID0_ICE +	lis	r4, 0 +	ori	r4, r4, HID0_ILOCK +	andc	r3, r3, r4 +	ori	r4, r3, HID0_ICFI +	isync +	mtspr	HID0, r4    /* sets enable and invalidate, clears lock */ +	isync +	mtspr	HID0, r3	/* clears invalidate */ +	blr + +	.globl	icache_disable +icache_disable: +	mfspr	r3, HID0 +	lis	r4, 0 +	ori	r4, r4, HID0_ICE|HID0_ILOCK +	andc	r3, r3, r4 +	ori	r4, r3, HID0_ICFI +	isync +	mtspr	HID0, r4     /* sets invalidate, clears enable and lock*/ +	isync +	mtspr	HID0, r3	/* clears invalidate */ +	blr + +	.globl	icache_status +icache_status: +	mfspr	r3, HID0 +	rlwinm	r3, r3, (31 - HID0_ICE_SHIFT + 1), 31, 31 +	blr + +	.globl	dcache_enable +dcache_enable: +	mfspr	r3, HID0 +	li	r5, HID0_DCFI|HID0_DLOCK +	andc	r3, r3, r5 +	mtspr	HID0, r3		/* no invalidate, unlock */ +	ori	r3, r3, HID0_DCE +	ori	r5, r3, HID0_DCFI +	mtspr	HID0, r5		/* enable + invalidate */ +	mtspr	HID0, r3		/* enable */ +	sync +	blr + +	.globl	dcache_disable +dcache_disable: +	mfspr	r3, HID0 +	lis	r4, 0 +	ori	r4, r4, HID0_DCE|HID0_DLOCK +	andc	r3, r3, r4 +	ori	r4, r3, HID0_DCI +	sync +	mtspr	HID0, r4	/* sets invalidate, clears enable and lock */ +	sync +	mtspr	HID0, r3	/* clears invalidate */ +	blr + +	.globl	dcache_status +dcache_status: +	mfspr	r3, HID0 +	rlwinm	r3, r3, (31 - HID0_DCE_SHIFT + 1), 31, 31 +	blr + +	.globl get_pvr +get_pvr: +	mfspr	r3, PVR +	blr + +/*-------------------------------------------------------------------*/ + +/* + * void relocate_code (addr_sp, gd, addr_moni) + * + * This "function" does not return, instead it continues in RAM + * after relocating the monitor code. + * + * r3 = dest + * r4 = src + * r5 = length in bytes + * r6 = cachelinesize + */ +	.globl	relocate_code +relocate_code: +	mr	r1,  r3		/* Set new stack pointer	*/ +	mr	r9,  r4		/* Save copy of Global Data pointer */ +	mr	r10, r5		/* Save copy of Destination Address */ + +	GET_GOT +	mr	r3,  r5				/* Destination Address */ +	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 +	/* then 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) + +	/* copy */ +1:	lwzu	r0,4(r8) +	stwu	r0,4(r7) +	bdnz	1b + +	addi	r0,r5,3 +	srwi.	r0,r0,2 +	mtctr	r0 +	la	r8,-4(r4) +	la	r7,-4(r3) + +	/* and compare */ +20:	lwzu	r20,4(r8) +	lwzu	r21,4(r7) +	xor. r22, r20, r21 +	bne  30f +	bdnz	20b +	b 4f + +	/* compare failed */ +30:	li r3, 0 +	blr + +2:	slwi	r0,r0,2 /* re copy in reverse order ... y do we needed it? */ +	add	r8,r4,r0 +	add	r7,r3,r0 +3:	lwzu	r0,-4(r8) +	stwu	r0,-4(r7) +	bdnz	3b + +/* + * Now flush the cache: note that we must start from a cache aligned + * address. Otherwise we might miss one cache line. + */ +4:	cmpwi	r6,0 +	add	r5,r3,r5 +	beq	7f		/* Always flush prefetch queue in any case */ +	subi	r0,r6,1 +	andc	r3,r3,r0 +	mr	r4,r3 +5:	dcbst	0,r4 +	add	r4,r4,r6 +	cmplw	r4,r5 +	blt	5b +	sync			/* Wait for all dcbst to complete on bus */ +	mr	r4,r3 +6:	icbi	0,r4 +	add	r4,r4,r6 +	cmplw	r4,r5 +	blt	6b +7:	sync			/* Wait for all icbi to complete on bus	*/ +	isync + +/* + * We are done. Do not return, instead branch to second part of board + * initialization, now running from RAM. + */ +	addi	r0, r10, in_ram - _start + EXC_OFF_SYS_RESET +	mtlr	r0 +	blr + +in_ram: +	/* +	 * Relocation Function, 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		/* Global Data pointer		*/ +	mr	r4, r10		/* Destination Address		*/ +	bl	board_init_r + +	/* +	 * Copy exception vector code to low memory +	 * +	 * r3: dest_addr +	 * r7: source address, r8: end address, r9: target address +	 */ +	.globl	trap_init +trap_init: +	mflr	r4		/* save link register */ +	GET_GOT +	lwz	r7, GOT(_start) +	lwz	r8, GOT(_end_of_vectors) + +	li	r9, 0x100	/* reset vector at 0x100 */ + +	cmplw	0, r7, r8 +	bgelr			/* return if r7>=r8 - just in case */ +1: +	lwz	r0, 0(r7) +	stw	r0, 0(r9) +	addi	r7, r7, 4 +	addi	r9, r9, 4 +	cmplw	0, r7, r8 +	bne	1b + +	/* +	 * relocate `hdlr' and `int_return' entries +	 */ +	li	r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET +	li	r8, Alignment - _start + EXC_OFF_SYS_RESET +2: +	bl	trap_reloc +	addi	r7, r7, 0x100		/* next exception vector */ +	cmplw	0, r7, r8 +	blt	2b + +	li	r7, .L_Alignment - _start + EXC_OFF_SYS_RESET +	bl	trap_reloc + +	li	r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET +	bl	trap_reloc + +	li	r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET +	li	r8, SystemCall - _start + EXC_OFF_SYS_RESET +3: +	bl	trap_reloc +	addi	r7, r7, 0x100		/* next exception vector */ +	cmplw	0, r7, r8 +	blt	3b + +	li	r7, .L_Trace - _start + EXC_OFF_SYS_RESET +	li	r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET +4: +	bl	trap_reloc +	addi	r7, r7, 0x100		/* next exception vector */ +	cmplw	0, r7, r8 +	blt	4b + +	mfmsr	r3			/* now that the vectors have */ +	lis	r7, MSR_IP@h		/* relocated into low memory */ +	ori	r7, r7, MSR_IP@l	/* MSR[IP] can be turned off */ +	andc	r3, r3, r7		/* (if it was on) */ +	SYNC				/* Some chip revs need this... */ +	mtmsr	r3 +	SYNC + +	mtlr	r4			/* restore link register    */ +	blr diff --git a/arch/powerpc/cpu/mpc512x/traps.c b/arch/powerpc/cpu/mpc512x/traps.c new file mode 100644 index 000000000..786f4a5a7 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/traps.c @@ -0,0 +1,212 @@ +/* + * (C) Copyright 2000 - 2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org) + * + * 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 + * + * Derived from the MPC83xx code. + */ + +/* + * This file handles the architecture-dependent parts of hardware + * exceptions + */ + +#include <common.h> +#include <kgdb.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +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()) + +/* + * Trap & Exception support + */ + +void +print_backtrace (unsigned long *sp) +{ +	int cnt = 0; +	unsigned long i; + +	puts ("Call backtrace: "); +	while (sp) { +		if ((uint)sp > END_OF_MEM) +			break; + +		i = sp[1]; +		if (cnt++ % 7 == 0) +			putc ('\n'); +		printf ("%08lX ", i); +		if (cnt > 32) break; +		sp = (unsigned long *) *sp; +	} +	putc ('\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); + +	putc ('\n'); +	for (i = 0;  i < 32;  i++) { +		if ((i % 8) == 0) { +			printf ("GPR%02d: ", i); +		} + +		printf ("%08lX ", regs->gpr[i]); +		if ((i % 8) == 7) { +			putc ('\n'); +		} +	} +} + + +void +_exception (int signr, struct pt_regs *regs) +{ +	show_regs (regs); +	print_backtrace ((unsigned long *)regs->gpr[1]); +	panic ("Exception at pc %lx signal %d", regs->nip,signr); +} + + +void +MachineCheckException (struct pt_regs *regs) +{ +	unsigned long fixup; + +	if ((fixup = search_exception_table (regs->nip)) != 0) { +		regs->nip = fixup; +		return; +	} + +#ifdef CONFIG_CMD_KGDB +	if (debugger_exception_handler && (*debugger_exception_handler)(regs)) +		return; +#endif + +	puts ("Machine check.\nCaused by (from msr): "); +	printf ("regs %p ",regs); +	switch (regs->msr & 0x00FF0000) { +	case (0x80000000 >> 10): +		puts ("Instruction cache parity signal\n"); +		break; +	case (0x80000000 >> 11): +		puts ("Data cache parity signal\n"); +		break; +	case (0x80000000 >> 12): +		puts ("Machine check signal\n"); +		break; +	case (0x80000000 >> 13): +		puts ("Transfer error ack signal\n"); +		break; +	case (0x80000000 >> 14): +		puts ("Data parity signal\n"); +		break; +	case (0x80000000 >> 15): +		puts ("Address parity signal\n"); +		break; +	default: +		puts ("Unknown values in msr\n"); +	} +	show_regs (regs); +	print_backtrace ((unsigned long *)regs->gpr[1]); + +	panic ("machine check"); +} + +void +AlignmentException (struct pt_regs *regs) +{ +#ifdef 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) +{ +#ifdef CONFIG_CMD_KGDB +	if (debugger_exception_handler && (*debugger_exception_handler)(regs)) +		return; +#endif +	show_regs (regs); +	print_backtrace ((unsigned long *)regs->gpr[1]); +	panic ("Program Check Exception"); +} + +void +SoftEmuException (struct pt_regs *regs) +{ +#ifdef CONFIG_CMD_KGDB +	if (debugger_exception_handler && (*debugger_exception_handler)(regs)) +		return; +#endif +	show_regs (regs); +	print_backtrace ((unsigned long *)regs->gpr[1]); +	panic ("Software Emulation Exception"); +} + + +void +UnknownException (struct pt_regs *regs) +{ +#ifdef 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); +} + +#ifdef CONFIG_CMD_BEDBUG +extern void do_bedbug_breakpoint (struct pt_regs *); +#endif + +void +DebugException (struct pt_regs *regs) +{ +	printf ("Debugger trap at @ %lx\n", regs->nip ); +	show_regs (regs); +#ifdef CONFIG_CMD_BEDBUG +	do_bedbug_breakpoint (regs); +#endif +} diff --git a/arch/powerpc/cpu/mpc512x/u-boot.lds b/arch/powerpc/cpu/mpc512x/u-boot.lds new file mode 100644 index 000000000..c71679960 --- /dev/null +++ b/arch/powerpc/cpu/mpc512x/u-boot.lds @@ -0,0 +1,120 @@ +/* + * (C) Copyright 2007 DENX Software Engineering. + * + * 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 +{ +  /* Read-only sections, merged into text segment: */ +  . = + SIZEOF_HEADERS; +  .interp : { *(.interp) } +  .hash          : { *(.hash)		} +  .dynsym        : { *(.dynsym)		} +  .dynstr        : { *(.dynstr)		} +  .rel.text      : { *(.rel.text)		} +  .rela.text     : { *(.rela.text)	} +  .rel.data      : { *(.rel.data)		} +  .rela.data     : { *(.rela.data)	} +  .rel.rodata    : { *(.rel.rodata)	} +  .rela.rodata   : { *(.rela.rodata)	} +  .rel.got       : { *(.rel.got)		} +  .rela.got      : { *(.rela.got)		} +  .rel.ctors     : { *(.rel.ctors)	} +  .rela.ctors    : { *(.rela.ctors)	} +  .rel.dtors     : { *(.rel.dtors)	} +  .rela.dtors    : { *(.rela.dtors)	} +  .rel.bss       : { *(.rel.bss)		} +  .rela.bss      : { *(.rela.bss)		} +  .rel.plt       : { *(.rel.plt)		} +  .rela.plt      : { *(.rela.plt)		} +  .init          : { *(.init)	} +  .plt : { *(.plt) } +  .text      : +  { +    arch/powerpc/cpu/mpc512x/start.o	(.text) +    *(.text) +    *(.got1) +    . = ALIGN(16); +    *(.eh_frame) +    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) +  } +  .fini      : { *(.fini)    } =0 +  .ctors     : { *(.ctors)   } +  .dtors     : { *(.dtors)   } + +  /* Read-write section, merged into data segment: */ +  . = (. + 0x0FFF) & 0xFFFFF000; +  _erotext = .; +  PROVIDE (erotext = .); +  .reloc   : +  { +    *(.got) +    _GOT2_TABLE_ = .; +    *(.got2) +    _FIXUP_TABLE_ = .; +    *(.fixup) +  } +  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; +  __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + +  .data    : +  { +    *(.data) +    *(.data1) +    *(.sdata) +    *(.sdata2) +    *(.dynamic) +    CONSTRUCTORS +  } +  _edata  =  .; +  PROVIDE (edata = .); + +  . = .; +  __u_boot_cmd_start = .; +  .u_boot_cmd : { *(.u_boot_cmd) } +  __u_boot_cmd_end = .; + + +  . = .; +  __start___ex_table = .; +  __ex_table : { *(__ex_table) } +  __stop___ex_table = .; + +  . = ALIGN(4096); +  __init_begin = .; +  .text.init : { *(.text.init) } +  .data.init : { *(.data.init) } +  . = ALIGN(4096); +  __init_end = .; + +  __bss_start = .; +  .bss (NOLOAD)       : +  { +   *(.sbss) *(.scommon) +   *(.dynbss) +   *(.bss) +   *(COMMON) +   . = ALIGN(4); +  } +  _end = . ; +  PROVIDE (end = .); +} +ENTRY(_start) |