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 0000000000..1719c66e8d --- /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 0000000000..957d4be2d2 --- /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 0000000000..b29edb1b38 --- /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 0000000000..09cbd2024d --- /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 0000000000..fe6beaf84d --- /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 0000000000..93611615f1 --- /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 0000000000..442b5fc918 --- /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 0000000000..e2d909751e --- /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 0000000000..dd6b2f4673 --- /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 0000000000..8f2eb37e17 --- /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 0000000000..ef7c773b2b --- /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 0000000000..be20947623 --- /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 0000000000..141db8b865 --- /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 0000000000..ec2f41bb36 --- /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 0000000000..ce8d0949b2 --- /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 0000000000..d26b61707e --- /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 0000000000..786f4a5a7e --- /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 0000000000..c71679960c --- /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) |