diff options
author | wdenk <wdenk> | 2003-10-15 23:53:47 +0000 |
---|---|---|
committer | wdenk <wdenk> | 2003-10-15 23:53:47 +0000 |
commit | 42d1f0394bef0624fc9664714d54bb137931d6a6 (patch) | |
tree | 892a4130507484d25faf9a72e019cf88cfb3e3d9 /cpu/mpc85xx | |
parent | 2d5b561e2bfdee8552a99b2cf93016cce2a74895 (diff) | |
download | talos-obmc-uboot-42d1f0394bef0624fc9664714d54bb137931d6a6.tar.gz talos-obmc-uboot-42d1f0394bef0624fc9664714d54bb137931d6a6.zip |
* Patches by Xianghua Xiao, 15 Oct 2003:
- Added Motorola CPU 8540/8560 support (cpu/85xx)
- Added Motorola MPC8540ADS board support (board/mpc8540ads)
- Added Motorola MPC8560ADS board support (board/mpc8560ads)
* Minor code cleanup
Diffstat (limited to 'cpu/mpc85xx')
-rw-r--r-- | cpu/mpc85xx/Makefile | 45 | ||||
-rw-r--r-- | cpu/mpc85xx/commproc.c | 214 | ||||
-rw-r--r-- | cpu/mpc85xx/config.mk | 26 | ||||
-rw-r--r-- | cpu/mpc85xx/cpu.c | 151 | ||||
-rw-r--r-- | cpu/mpc85xx/cpu_init.c | 205 | ||||
-rw-r--r-- | cpu/mpc85xx/ether_fcc.c | 461 | ||||
-rw-r--r-- | cpu/mpc85xx/i2c.c | 288 | ||||
-rw-r--r-- | cpu/mpc85xx/interrupts.c | 138 | ||||
-rw-r--r-- | cpu/mpc85xx/pci.c | 107 | ||||
-rw-r--r-- | cpu/mpc85xx/resetvec.S | 2 | ||||
-rw-r--r-- | cpu/mpc85xx/serial_scc.c | 274 | ||||
-rw-r--r-- | cpu/mpc85xx/spd_sdram.c | 308 | ||||
-rw-r--r-- | cpu/mpc85xx/speed.c | 124 | ||||
-rw-r--r-- | cpu/mpc85xx/start.S | 1156 | ||||
-rw-r--r-- | cpu/mpc85xx/traps.c | 272 | ||||
-rw-r--r-- | cpu/mpc85xx/tsec.c | 441 | ||||
-rw-r--r-- | cpu/mpc85xx/tsec.h | 393 |
17 files changed, 4605 insertions, 0 deletions
diff --git a/cpu/mpc85xx/Makefile b/cpu/mpc85xx/Makefile new file mode 100644 index 0000000000..996915e11c --- /dev/null +++ b/cpu/mpc85xx/Makefile @@ -0,0 +1,45 @@ +# +# (C) Copyright 2002,2003 Motorola Inc. +# Xianghua Xiao,X.Xiao@motorola.com +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = lib$(CPU).a + +START = start.o resetvec.o +COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o tsec.o \ + pci.o serial_scc.o commproc.o ether_fcc.o i2c.o spd_sdram.o +OBJS = $(COBJS) + +all: .depend $(START) $(LIB) + +$(LIB): $(OBJS) + $(AR) crv $@ $(OBJS) + +######################################################################### + +.depend: Makefile $(START:.o=.S) $(AOBJS:.o=.S) $(COBJS:.o=.c) + $(CC) -M $(CFLAGS) $(START:.o=.S) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/cpu/mpc85xx/commproc.c b/cpu/mpc85xx/commproc.c new file mode 100644 index 0000000000..df11052f2a --- /dev/null +++ b/cpu/mpc85xx/commproc.c @@ -0,0 +1,214 @@ +/* + * Adapted for Motorola MPC8560 chips + * Xianghua Xiao <x.xiao@motorola.com> + * + * This file is based on "arch/ppc/8260_io/commproc.c" - here is it's + * copyright notice: + * + * General Purpose functions for the global management of the + * 8220 Communication Processor Module. + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) + * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com) + * 2.3.99 Updates + * Copyright (c) 2003 Motorola,Inc. + * + * In addition to the individual control of the communication + * channels, there are a few functions that globally affect the + * communication processor. + * + * Buffer descriptors must be allocated from the dual ported memory + * space. The allocator for that is here. When the communication + * process is reset, we reclaim the memory available. There is + * currently no deallocator for this memory. + */ +#include <common.h> +#include <asm/cpm_85xx.h> + +#if defined(CONFIG_MPC8560) +/* + * because we have stack and init data in dual port ram + * we must reduce the size + */ +#undef CPM_DATAONLY_SIZE +#define CPM_DATAONLY_SIZE ((uint)(8 * 1024) - CPM_DATAONLY_BASE) + +void +m8560_cpm_reset(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + volatile immap_t *immr = (immap_t *)CFG_IMMR; + volatile ulong count; + + gd = (gd_t *) (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET); + + /* Reclaim the DP memory for our use. + */ + gd->dp_alloc_base = CPM_DATAONLY_BASE; + gd->dp_alloc_top = gd->dp_alloc_base + CPM_DATAONLY_SIZE; + + /* + * Reset CPM + */ + immr->im_cpm.im_cpm_cp.cpcr = CPM_CR_RST; + count = 0; + do { /* Spin until command processed */ + __asm__ __volatile__ ("eieio"); + } while ((immr->im_cpm.im_cpm_cp.cpcr & CPM_CR_FLG) && ++count < 1000000); +} + +/* Allocate some memory from the dual ported ram. + * To help protocols with object alignment restrictions, we do that + * if they ask. + */ +uint +m8560_cpm_dpalloc(uint size, uint align) +{ + DECLARE_GLOBAL_DATA_PTR; + + volatile immap_t *immr = (immap_t *)CFG_IMMR; + uint retloc; + uint align_mask, off; + uint savebase; + + align_mask = align - 1; + savebase = gd->dp_alloc_base; + + if ((off = (gd->dp_alloc_base & align_mask)) != 0) + gd->dp_alloc_base += (align - off); + + if ((off = size & align_mask) != 0) + size += align - off; + + if ((gd->dp_alloc_base + size) >= gd->dp_alloc_top) { + gd->dp_alloc_base = savebase; + panic("m8560_cpm_dpalloc: ran out of dual port ram!"); + } + + retloc = gd->dp_alloc_base; + gd->dp_alloc_base += size; + + memset((void *)&(immr->im_cpm.im_dprambase[retloc]), 0, size); + + return(retloc); +} + +/* We also own one page of host buffer space for the allocation of + * UART "fifos" and the like. + */ +uint +m8560_cpm_hostalloc(uint size, uint align) +{ + /* the host might not even have RAM yet - just use dual port RAM */ + return (m8560_cpm_dpalloc(size, align)); +} + +/* Set a baud rate generator. This needs lots of work. There are + * eight BRGs, which can be connected to the CPM channels or output + * as clocks. The BRGs are in two different block of internal + * memory mapped space. + * The baud rate clock is the system clock divided by something. + * It was set up long ago during the initial boot phase and is + * is given to us. + * Baud rate clocks are zero-based in the driver code (as that maps + * to port numbers). Documentation uses 1-based numbering. + */ +#define BRG_INT_CLK gd->brg_clk +#define BRG_UART_CLK ((BRG_INT_CLK + 15) / 16) + +/* This function is used by UARTS, or anything else that uses a 16x + * oversampled clock. + */ +void +m8560_cpm_setbrg(uint brg, uint rate) +{ + DECLARE_GLOBAL_DATA_PTR; + + volatile immap_t *immr = (immap_t *)CFG_IMMR; + volatile uint *bp; + + /* This is good enough to get SMCs running..... + */ + if (brg < 4) { + bp = (uint *)&(immr->im_cpm.im_cpm_brg1.brgc1); + } + else { + bp = (uint *)&(immr->im_cpm.im_cpm_brg2.brgc5); + brg -= 4; + } + bp += brg; + *bp = (((((BRG_UART_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN; +} + +/* This function is used to set high speed synchronous baud rate + * clocks. + */ +void +m8560_cpm_fastbrg(uint brg, uint rate, int div16) +{ + DECLARE_GLOBAL_DATA_PTR; + + volatile immap_t *immr = (immap_t *)CFG_IMMR; + volatile uint *bp; + + /* This is good enough to get SMCs running..... + */ + if (brg < 4) { + bp = (uint *)&(immr->im_cpm.im_cpm_brg1.brgc1); + } + else { + bp = (uint *)&(immr->im_cpm.im_cpm_brg2.brgc5); + brg -= 4; + } + bp += brg; + *bp = (((((BRG_INT_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN; + if (div16) + *bp |= CPM_BRG_DIV16; +} + +/* This function is used to set baud rate generators using an external + * clock source and 16x oversampling. + */ + +void +m8560_cpm_extcbrg(uint brg, uint rate, uint extclk, int pinsel) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + volatile uint *bp; + + if (brg < 4) { + bp = (uint *)&(immr->im_cpm.im_cpm_brg1.brgc1); + } + else { + bp = (uint *)&(immr->im_cpm.im_cpm_brg2.brgc5); + brg -= 4; + } + bp += brg; + *bp = ((((((extclk/16)+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN; + if (pinsel == 0) + *bp |= CPM_BRG_EXTC_CLK3_9; + else + *bp |= CPM_BRG_EXTC_CLK5_15; +} + +#ifdef CONFIG_POST + +void post_word_store (ulong a) +{ + volatile ulong *save_addr = + (volatile ulong *)(CFG_IMMR + CPM_POST_WORD_ADDR); + + *save_addr = a; +} + +ulong post_word_load (void) +{ + volatile ulong *save_addr = + (volatile ulong *)(CFG_IMMR + CPM_POST_WORD_ADDR); + + return *save_addr; +} + +#endif /* CONFIG_POST */ + +#endif /* CONFIG_MPC8560 */ diff --git a/cpu/mpc85xx/config.mk b/cpu/mpc85xx/config.mk new file mode 100644 index 0000000000..c12e923066 --- /dev/null +++ b/cpu/mpc85xx/config.mk @@ -0,0 +1,26 @@ +# +# (C) Copyright 2002,2003 Motorola Inc. +# Xianghua Xiao, X.Xiao@motorola.com +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +PLATFORM_RELFLAGS += -mrelocatable -ffixed-r14 -meabi + +PLATFORM_CPPFLAGS += -DCONFIG_MPC85xx -DCONFIG_E500 -ffixed-r2 -ffixed-r29 -Wa,-me500 -msoft-float diff --git a/cpu/mpc85xx/cpu.c b/cpu/mpc85xx/cpu.c new file mode 100644 index 0000000000..64f27820a2 --- /dev/null +++ b/cpu/mpc85xx/cpu.c @@ -0,0 +1,151 @@ +/* + * (C) Copyright 2002, 2003 Motorola Inc. + * Xianghua Xiao (X.Xiao@motorola.com) + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <watchdog.h> +#include <command.h> +#include <asm/cache.h> + +/* ------------------------------------------------------------------------- */ + +int checkcpu (void) +{ + uint pir = get_pir(); + uint pvr = get_pvr(); + + printf("Motorola PowerPC ProcessorID=%08x Rev. ",pir); + switch(pvr) { + default: + printf("PVR=%08x", pvr); + break; + } + + printf("\n"); + + return 0; +} + + +/* ------------------------------------------------------------------------- */ + +int do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]) +{ + /* + * Initiate hard reset in debug control register DBCR0 + * Make sure MSR[DE] = 1 + */ + __asm__ __volatile__("lis 3, 0x7000" ::: "r3"); + mtspr(DBCR0,3); + return 1; +} + + +/* + * Get timebase clock frequency + */ +unsigned long get_tbclk (void) +{ + + sys_info_t sys_info; + + get_sys_info(&sys_info); + return ((sys_info.freqSystemBus + 3L) / 4L); +} + + +#if defined(CONFIG_WATCHDOG) +void +watchdog_reset(void) +{ + int re_enable = disable_interrupts(); + reset_85xx_watchdog(); + if (re_enable) enable_interrupts(); +} + +void +reset_85xx_watchdog(void) +{ + /* + * Clear TSR(WIS) bit by writing 1 + */ + unsigned long val; + val = mfspr(tsr); + val |= 0x40000000; + mtspr(tsr, val); +} +#endif /* CONFIG_WATCHDOG */ + +#if defined(CONFIG_DDR_ECC) +__inline__ void dcbz(const void* addr) +{ + __asm__ __volatile__ ("dcbz 0,%0" :: "r" (addr)); +} + +__inline__ void dcbf(const void* addr) +{ + __asm__ __volatile__ ("dcbf 0,%0" :: "r" (addr)); +} + +void dma_init(void) { + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile ccsr_dma_t *dma = &immap->im_dma; + + dma->satr0 = 0x02c40000; + dma->datr0 = 0x02c40000; + asm("sync; isync; msync"); + return; +} + +uint dma_check(void) { + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile ccsr_dma_t *dma = &immap->im_dma; + volatile uint status = dma->sr0; + + /* While the channel is busy, spin */ + while((status & 4) == 4) { + status = dma->sr0; + } + + if (status != 0) { + printf ("DMA Error: status = %x\n", status); + } + return status; +} + +int dma_xfer(void *dest, uint count, void *src) { + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile ccsr_dma_t *dma = &immap->im_dma; + + dma->dar0 = (uint) dest; + dma->sar0 = (uint) src; + dma->bcr0 = count; + dma->mr0 = 0xf000004; + asm("sync;isync;msync"); + dma->mr0 = 0xf000005; + asm("sync;isync;msync"); + return dma_check(); +} +#endif diff --git a/cpu/mpc85xx/cpu_init.c b/cpu/mpc85xx/cpu_init.c new file mode 100644 index 0000000000..3ffd55880f --- /dev/null +++ b/cpu/mpc85xx/cpu_init.c @@ -0,0 +1,205 @@ +/* + * (C) Copyright 2003 Motorola Inc. + * Modified by Xianghua Xiao, X.Xiao@motorola.com + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <watchdog.h> +#include <asm/processor.h> +#include <ioports.h> +#include <asm/io.h> + +#ifdef CONFIG_MPC8560 +static void config_8560_ioports (volatile immap_t * immr) +{ + int portnum; + + for (portnum = 0; portnum < 4; portnum++) { + uint pmsk = 0, + ppar = 0, + psor = 0, + pdir = 0, + podr = 0, + pdat = 0; + iop_conf_t *iopc = (iop_conf_t *) & iop_conf_tab[portnum][0]; + iop_conf_t *eiopc = iopc + 32; + uint msk = 1; + + /* + * NOTE: + * index 0 refers to pin 31, + * index 31 refers to pin 0 + */ + while (iopc < eiopc) { + if (iopc->conf) { + pmsk |= msk; + if (iopc->ppar) + ppar |= msk; + if (iopc->psor) + psor |= msk; + if (iopc->pdir) + pdir |= msk; + if (iopc->podr) + podr |= msk; + if (iopc->pdat) + pdat |= msk; + } + + msk <<= 1; + iopc++; + } + + if (pmsk != 0) { + volatile ioport_t *iop = ioport_addr (immr, portnum); + uint tpmsk = ~pmsk; + + /* + * the (somewhat confused) paragraph at the + * bottom of page 35-5 warns that there might + * be "unknown behaviour" when programming + * PSORx and PDIRx, if PPARx = 1, so I + * decided this meant I had to disable the + * dedicated function first, and enable it + * last. + */ + iop->ppar &= tpmsk; + iop->psor = (iop->psor & tpmsk) | psor; + iop->podr = (iop->podr & tpmsk) | podr; + iop->pdat = (iop->pdat & tpmsk) | pdat; + iop->pdir = (iop->pdir & tpmsk) | pdir; + iop->ppar |= ppar; + } + } +} +#endif + +/* + * Breathe some life into the CPU... + * + * Set up the memory map + * initialize a bunch of registers + */ + +void cpu_init_f (void) +{ + DECLARE_GLOBAL_DATA_PTR; + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile ccsr_lbc_t *memctl = &immap->im_lbc; + extern void m8560_cpm_reset (void); + + /* Pointer is writable since we allocated a register for it */ + gd = (gd_t *) (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET); + + /* Clear initial global data */ + memset ((void *) gd, 0, sizeof (gd_t)); + + +#ifdef CONFIG_MPC8560 + config_8560_ioports(immap); +#endif + + /* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary + * addresses - these have to be modified later when FLASH size + * has been determined + */ +#if defined(CFG_OR0_REMAP) + memctl->or0 = CFG_OR0_REMAP; +#endif +#if defined(CFG_OR1_REMAP) + memctl->or1 = CFG_OR1_REMAP; +#endif + + /* now restrict to preliminary range */ +#if defined(CFG_BR0_PRELIM) && defined(CFG_OR0_PRELIM) + memctl->br0 = CFG_BR0_PRELIM; + memctl->or0 = CFG_OR0_PRELIM; +#endif + +#if defined(CFG_BR1_PRELIM) && defined(CFG_OR1_PRELIM) + memctl->or1 = CFG_OR1_PRELIM; + memctl->br1 = CFG_BR1_PRELIM; +#endif + +#if !defined(CONFIG_MPC85xx) +#if defined(CFG_BR2_PRELIM) && defined(CFG_OR2_PRELIM) + memctl->or2 = CFG_OR2_PRELIM; + memctl->br2 = CFG_BR2_PRELIM; +#endif +#endif + +#if defined(CFG_BR3_PRELIM) && defined(CFG_OR3_PRELIM) + memctl->or3 = CFG_OR3_PRELIM; + memctl->br3 = CFG_BR3_PRELIM; +#endif + +#if defined(CFG_BR4_PRELIM) && defined(CFG_OR4_PRELIM) + memctl->or4 = CFG_OR4_PRELIM; + memctl->br4 = CFG_BR4_PRELIM; +#endif + +#if defined(CFG_BR5_PRELIM) && defined(CFG_OR5_PRELIM) + memctl->or5 = CFG_OR5_PRELIM; + memctl->br5 = CFG_BR5_PRELIM; +#endif + +#if defined(CFG_BR6_PRELIM) && defined(CFG_OR6_PRELIM) + memctl->or6 = CFG_OR6_PRELIM; + memctl->br6 = CFG_BR6_PRELIM; +#endif + +#if defined(CFG_BR7_PRELIM) && defined(CFG_OR7_PRELIM) + memctl->or7 = CFG_OR7_PRELIM; + memctl->br7 = CFG_BR7_PRELIM; +#endif + +#if defined(CONFIG_MPC8560) + m8560_cpm_reset(); +#endif +} + +/* + * We initialize L2 as cache here. + */ +int cpu_init_r (void) +{ +#if defined(CONFIG_L2_CACHE) + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile ccsr_l2cache_t *l2cache = &immap->im_l2cache; + volatile uint temp; + + asm("msync;isync"); + l2cache->l2ctl = 0x68000000; /* invalidate */ + temp = l2cache->l2ctl; + asm("msync;isync"); + l2cache->l2ctl = 0xa8000000; /* enable 256KB L2 cache */ + temp = l2cache->l2ctl; + asm("msync;isync"); + + printf("L2 cache enabled: 256KB\n"); +#else + printf("L2 cache disabled.\n"); +#endif + + return 0; +} diff --git a/cpu/mpc85xx/ether_fcc.c b/cpu/mpc85xx/ether_fcc.c new file mode 100644 index 0000000000..f78e5b4d7a --- /dev/null +++ b/cpu/mpc85xx/ether_fcc.c @@ -0,0 +1,461 @@ +/* + * MPC8560 FCC Fast Ethernet + * Copyright (c) 2003 Motorola,Inc. + * Xianghua Xiao, (X.Xiao@motorola.com) + * + * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net) + * + * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * MPC8560 FCC Fast Ethernet + * Basic ET HW initialization and packet RX/TX routines + * + * This code will not perform the IO port configuration. This should be + * done in the iop_conf_t structure specific for the board. + * + * TODO: + * add a PHY driver to do the negotiation + * reflect negotiation results in FPSMR + * look for ways to configure the board specific stuff elsewhere, eg. + * config_xxx.h or the board directory + */ + +#include <common.h> +#include <malloc.h> +#include <asm/cpm_85xx.h> +#include <command.h> +#include <config.h> +#include <net.h> + +#if defined(CONFIG_MPC8560) + +#if defined(CONFIG_ETHER_ON_FCC) && (CONFIG_COMMANDS & CFG_CMD_NET) && \ + defined(CONFIG_NET_MULTI) + +static struct ether_fcc_info_s +{ + int ether_index; + int proff_enet; + ulong cpm_cr_enet_sblock; + ulong cpm_cr_enet_page; + ulong cmxfcr_mask; + ulong cmxfcr_value; +} + ether_fcc_info[] = +{ +#ifdef CONFIG_ETHER_ON_FCC1 +{ + 0, + PROFF_FCC1, + CPM_CR_FCC1_SBLOCK, + CPM_CR_FCC1_PAGE, + CFG_CMXFCR_MASK1, + CFG_CMXFCR_VALUE1 +}, +#endif + +#ifdef CONFIG_ETHER_ON_FCC2 +{ + 1, + PROFF_FCC2, + CPM_CR_FCC2_SBLOCK, + CPM_CR_FCC2_PAGE, + CFG_CMXFCR_MASK2, + CFG_CMXFCR_VALUE2 +}, +#endif + +#ifdef CONFIG_ETHER_ON_FCC3 +{ + 2, + PROFF_FCC3, + CPM_CR_FCC3_SBLOCK, + CPM_CR_FCC3_PAGE, + CFG_CMXFCR_MASK3, + CFG_CMXFCR_VALUE3 +}, +#endif +}; + +/*---------------------------------------------------------------------*/ + +/* Maximum input DMA size. Must be a should(?) be a multiple of 4. */ +#define PKT_MAXDMA_SIZE 1520 + +/* The FCC stores dest/src/type, data, and checksum for receive packets. */ +#define PKT_MAXBUF_SIZE 1518 +#define PKT_MINBUF_SIZE 64 + +/* Maximum input buffer size. Must be a multiple of 32. */ +#define PKT_MAXBLR_SIZE 1536 + +#define TOUT_LOOP 1000000 + +#define TX_BUF_CNT 2 + +static uint rxIdx; /* index of the current RX buffer */ +static uint txIdx; /* index of the current TX buffer */ + +/* + * FCC Ethernet Tx and Rx buffer descriptors. + * Provide for Double Buffering + * Note: PKTBUFSRX is defined in net.h + */ + +typedef volatile struct rtxbd { + cbd_t rxbd[PKTBUFSRX]; + cbd_t txbd[TX_BUF_CNT]; +} RTXBD; + +/* Good news: the FCC supports external BDs! */ +#ifdef __GNUC__ +static RTXBD rtx __attribute__ ((aligned(8))); +#else +#error "rtx must be 64-bit aligned" +#endif + +#define ET_DEBUG + +static int fec_send(struct eth_device* dev, volatile void *packet, int length) +{ + int i = 0; + int result = 0; + + if (length <= 0) { + printf("fec: bad packet size: %d\n", length); + goto out; + } + + for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) { + if (i >= TOUT_LOOP) { + printf("fec: tx buffer not ready\n"); + goto out; + } + } + + rtx.txbd[txIdx].cbd_bufaddr = (uint)packet; + rtx.txbd[txIdx].cbd_datlen = length; + rtx.txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST | \ + BD_ENET_TX_TC ); + + for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) { + if (i >= TOUT_LOOP) { + printf("fec: tx error\n"); + goto out; + } + } + +#ifdef ET_DEBUG + printf("cycles: 0x%x txIdx=0x%04x status: 0x%04x\n", i, txIdx,rtx.txbd[txIdx].cbd_sc); + printf("packets at 0x%08x, length_in_bytes=0x%x\n",(uint)packet,length); + for(i=0;i<(length/16 + 1);i++) { + printf("%08x %08x %08x %08x\n",*((uint *)rtx.txbd[txIdx].cbd_bufaddr+i*4),\ + *((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 1),*((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 2), \ + *((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 3)); + } +#endif + + /* return only status bits */ + result = rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_STATS; + txIdx = (txIdx + 1) % TX_BUF_CNT; + +out: + return result; +} + +static int fec_recv(struct eth_device* dev) +{ + int length; + + for (;;) + { + if (rtx.rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) { + length = -1; + break; /* nothing received - leave for() loop */ + } + length = rtx.rxbd[rxIdx].cbd_datlen; + + if (rtx.rxbd[rxIdx].cbd_sc & 0x003f) { + printf("fec: rx error %04x\n", rtx.rxbd[rxIdx].cbd_sc); + } + else { + /* Pass the packet up to the protocol layers. */ + NetReceive(NetRxPackets[rxIdx], length - 4); + } + + + /* Give the buffer back to the FCC. */ + rtx.rxbd[rxIdx].cbd_datlen = 0; + + /* wrap around buffer index when necessary */ + if ((rxIdx + 1) >= PKTBUFSRX) { + rtx.rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); + rxIdx = 0; + } + else { + rtx.rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY; + rxIdx++; + } + } + return length; +} + + +static int fec_init(struct eth_device* dev, bd_t *bis) +{ + struct ether_fcc_info_s * info = dev->priv; + int i; + volatile immap_t *immr = (immap_t *)CFG_IMMR; + volatile ccsr_cpm_cp_t *cp = &(immr->im_cpm.im_cpm_cp); + fcc_enet_t *pram_ptr; + unsigned long mem_addr; + +#if 0 + mii_discover_phy(); +#endif + + /* 28.9 - (1-2): ioports have been set up already */ + + /* 28.9 - (3): connect FCC's tx and rx clocks */ + immr->im_cpm.im_cpm_mux.cmxuar = 0; /* ATM */ + immr->im_cpm.im_cpm_mux.cmxfcr = (immr->im_cpm.im_cpm_mux.cmxfcr & ~info->cmxfcr_mask) | + info->cmxfcr_value; + + /* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, set Mode Ethernet */ + if(info->ether_index == 0) { + immr->im_cpm.im_cpm_fcc1.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32; + } else if (info->ether_index == 1) { + immr->im_cpm.im_cpm_fcc2.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32; + } else if (info->ether_index == 2) { + immr->im_cpm.im_cpm_fcc3.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32; + } + + /* 28.9 - (5): FPSMR: enable full duplex, select CCITT CRC for Ethernet,MII */ + if(info->ether_index == 0) { + immr->im_cpm.im_cpm_fcc1.fpsmr = CFG_FCC_PSMR | FCC_PSMR_ENCRC; + } else if (info->ether_index == 1){ + immr->im_cpm.im_cpm_fcc2.fpsmr = CFG_FCC_PSMR | FCC_PSMR_ENCRC; + } else if (info->ether_index == 2){ + immr->im_cpm.im_cpm_fcc3.fpsmr = CFG_FCC_PSMR | FCC_PSMR_ENCRC; + } + + /* 28.9 - (6): FDSR: Ethernet Syn */ + if(info->ether_index == 0) { + immr->im_cpm.im_cpm_fcc1.fdsr = 0xD555; + } else if (info->ether_index == 1) { + immr->im_cpm.im_cpm_fcc2.fdsr = 0xD555; + } else if (info->ether_index == 2) { + immr->im_cpm.im_cpm_fcc3.fdsr = 0xD555; + } + + /* reset indeces to current rx/tx bd (see eth_send()/eth_rx()) */ + rxIdx = 0; + txIdx = 0; + + /* Setup Receiver Buffer Descriptors */ + for (i = 0; i < PKTBUFSRX; i++) + { + rtx.rxbd[i].cbd_sc = BD_ENET_RX_EMPTY; + rtx.rxbd[i].cbd_datlen = 0; + rtx.rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i]; + } + rtx.rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP; + + /* Setup Ethernet Transmitter Buffer Descriptors */ + for (i = 0; i < TX_BUF_CNT; i++) + { + rtx.txbd[i].cbd_sc = 0; + rtx.txbd[i].cbd_datlen = 0; + rtx.txbd[i].cbd_bufaddr = 0; + } + rtx.txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP; + + /* 28.9 - (7): initialize parameter ram */ + pram_ptr = (fcc_enet_t *)&(immr->im_cpm.im_dprambase[info->proff_enet]); + + /* clear whole structure to make sure all reserved fields are zero */ + memset((void*)pram_ptr, 0, sizeof(fcc_enet_t)); + + /* + * common Parameter RAM area + * + * Allocate space in the reserved FCC area of DPRAM for the + * internal buffers. No one uses this space (yet), so we + * can do this. Later, we will add resource management for + * this area. CPM_FCC_SPECIAL_BASE: 0xb000. + */ + mem_addr = CPM_FCC_SPECIAL_BASE + ((info->ether_index) * 64); + pram_ptr->fen_genfcc.fcc_riptr = mem_addr; + pram_ptr->fen_genfcc.fcc_tiptr = mem_addr+32; + /* + * Set maximum bytes per receive buffer. + * It must be a multiple of 32. + */ + pram_ptr->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE; /* 1536 */ + /* localbus SDRAM should be preferred */ + pram_ptr->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB | + CFG_CPMFCR_RAMTYPE) << 24; + pram_ptr->fen_genfcc.fcc_rbase = (unsigned int)(&rtx.rxbd[rxIdx]); + pram_ptr->fen_genfcc.fcc_rbdstat = 0; + pram_ptr->fen_genfcc.fcc_rbdlen = 0; + pram_ptr->fen_genfcc.fcc_rdptr = 0; + /* localbus SDRAM should be preferred */ + pram_ptr->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB | + CFG_CPMFCR_RAMTYPE) << 24; + pram_ptr->fen_genfcc.fcc_tbase = (unsigned int)(&rtx.txbd[txIdx]); + pram_ptr->fen_genfcc.fcc_tbdstat = 0; + pram_ptr->fen_genfcc.fcc_tbdlen = 0; + pram_ptr->fen_genfcc.fcc_tdptr = 0; + + /* protocol-specific area */ + pram_ptr->fen_statbuf = 0x0; + pram_ptr->fen_cmask = 0xdebb20e3; /* CRC mask */ + pram_ptr->fen_cpres = 0xffffffff; /* CRC preset */ + pram_ptr->fen_crcec = 0; + pram_ptr->fen_alec = 0; + pram_ptr->fen_disfc = 0; + pram_ptr->fen_retlim = 15; /* Retry limit threshold */ + pram_ptr->fen_retcnt = 0; + pram_ptr->fen_pper = 0; + pram_ptr->fen_boffcnt = 0; + pram_ptr->fen_gaddrh = 0; + pram_ptr->fen_gaddrl = 0; + pram_ptr->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ + /* + * Set Ethernet station address. + * + * This is supplied in the board information structure, so we + * copy that into the controller. + * So far we have only been given one Ethernet address. We make + * it unique by setting a few bits in the upper byte of the + * non-static part of the address. + */ +#define ea eth_get_dev()->enetaddr + pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4]; + pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2]; + pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0]; +#undef ea + pram_ptr->fen_ibdcount = 0; + pram_ptr->fen_ibdstart = 0; + pram_ptr->fen_ibdend = 0; + pram_ptr->fen_txlen = 0; + pram_ptr->fen_iaddrh = 0; /* disable hash */ + pram_ptr->fen_iaddrl = 0; + pram_ptr->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register: 64 */ + /* pad pointer. use tiptr since we don't need a specific padding char */ + pram_ptr->fen_padptr = pram_ptr->fen_genfcc.fcc_tiptr; + pram_ptr->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length:1520 */ + pram_ptr->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length:1520 */ + +#if defined(ET_DEBUG) + printf("parm_ptr(0xff788500) = %p\n",pram_ptr); + printf("pram_ptr->fen_genfcc.fcc_rbase %08x\n", + pram_ptr->fen_genfcc.fcc_rbase); + printf("pram_ptr->fen_genfcc.fcc_tbase %08x\n", + pram_ptr->fen_genfcc.fcc_tbase); +#endif + + /* 28.9 - (8)(9): clear out events in FCCE */ + /* 28.9 - (9): FCCM: mask all events */ + if(info->ether_index == 0) { + immr->im_cpm.im_cpm_fcc1.fcce = ~0x0; + immr->im_cpm.im_cpm_fcc1.fccm = 0; + } else if (info->ether_index == 1) { + immr->im_cpm.im_cpm_fcc2.fcce = ~0x0; + immr->im_cpm.im_cpm_fcc2.fccm = 0; + } else if (info->ether_index == 2) { + immr->im_cpm.im_cpm_fcc3.fcce = ~0x0; + immr->im_cpm.im_cpm_fcc3.fccm = 0; + } + + /* 28.9 - (10-12): we don't use ethernet interrupts */ + + /* 28.9 - (13) + * + * Let's re-initialize the channel now. We have to do it later + * than the manual describes because we have just now finished + * the BD initialization. + */ + cp->cpcr = mk_cr_cmd(info->cpm_cr_enet_page, + info->cpm_cr_enet_sblock, + 0x0c, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + do { + __asm__ __volatile__ ("eieio"); + } while (cp->cpcr & CPM_CR_FLG); + + /* 28.9 - (14): enable tx/rx in gfmr */ + if(info->ether_index == 0) { + immr->im_cpm.im_cpm_fcc1.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR; + } else if (info->ether_index == 1) { + immr->im_cpm.im_cpm_fcc2.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR; + } else if (info->ether_index == 2) { + immr->im_cpm.im_cpm_fcc3.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR; + } + + return 0; +} + +static void fec_halt(struct eth_device* dev) +{ + struct ether_fcc_info_s * info = dev->priv; + volatile immap_t *immr = (immap_t *)CFG_IMMR; + + /* write GFMR: disable tx/rx */ + if(info->ether_index == 0) { + immr->im_cpm.im_cpm_fcc1.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR); + } else if(info->ether_index == 1) { + immr->im_cpm.im_cpm_fcc2.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR); + } else if(info->ether_index == 2) { + immr->im_cpm.im_cpm_fcc3.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR); + } +} + +int fec_initialize(bd_t *bis) +{ + struct eth_device* dev; + int i; + + for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++) + { + dev = (struct eth_device*) malloc(sizeof *dev); + memset(dev, 0, sizeof *dev); + + sprintf(dev->name, "FCC%d ETHERNET", + ether_fcc_info[i].ether_index + 1); + dev->priv = ðer_fcc_info[i]; + dev->init = fec_init; + dev->halt = fec_halt; + dev->send = fec_send; + dev->recv = fec_recv; + + eth_register(dev); + } + + return 1; +} + +#endif /* CONFIG_ETHER_ON_FCC && CFG_CMD_NET && CONFIG_NET_MULTI */ + +#endif /* CONFIG_MPC8560 */ diff --git a/cpu/mpc85xx/i2c.c b/cpu/mpc85xx/i2c.c new file mode 100644 index 0000000000..ae08d18832 --- /dev/null +++ b/cpu/mpc85xx/i2c.c @@ -0,0 +1,288 @@ +/* + * (C) Copyright 2003,Motorola Inc. + * Xianghua Xiao <x.xiao@motorola.com> + * Adapted for Motorola 85xx chip. + * + * (C) Copyright 2003 + * Gleb Natapov <gnatapov@mrv.com> + * Some bits are taken from linux driver writen by adrian@humboldt.co.uk + * + * Hardware I2C driver for MPC107 PCI bridge. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> + +#define DEBUG + +#if defined(DEBUG) +#define DEB(x) x +#else +#define DEB(x) +#endif + +#ifdef CONFIG_HARD_I2C +#include <i2c.h> + +#define TIMEOUT (CFG_HZ/4) + +#define I2C_Addr ((unsigned *)(CFG_CCSRBAR + 0x3000)) + +#define I2CADR &I2C_Addr[0] +#define I2CFDR &I2C_Addr[1] +#define I2CCCR &I2C_Addr[2] +#define I2CCSR &I2C_Addr[3] +#define I2CCDR &I2C_Addr[4] +#define I2CDFSRR &I2C_Addr[5] + +#define I2C_READ 1 +#define I2C_WRITE 0 + +/* taken from linux include/asm-ppc/io.h */ +inline unsigned in_le32(volatile unsigned *addr) +{ + unsigned ret; + + __asm__ __volatile__("lwbrx %0,0,%1;\n" + "twi 0,%0,0;\n" + "isync" : "=r" (ret) : + "r" (addr), "m" (*addr)); + return ret; +} + +inline void out_le32(volatile unsigned *addr, int val) +{ + __asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) : + "r" (val), "r" (addr)); +} + +#define writel(val, addr) out_le32(addr, val) +#define readl(addr) in_le32(addr) + +void +i2c_init(int speed, int slaveadd) +{ + /* stop I2C controller */ + writel (0x0, I2CCCR); + /* set clock */ + writel (0x3f, I2CFDR); + /* set default filter */ + writel (0x10,I2CDFSRR); + /* write slave address */ + writel (slaveadd, I2CADR); + /* clear status register */ + writel (0x0, I2CCSR); + /* start I2C controller */ + writel (MPC85xx_I2CCR_MEN, I2CCCR); +} + +static __inline__ int +i2c_wait4bus (void) +{ + ulong timeval = get_timer (0); + + while (readl (I2CCSR) & MPC85xx_I2CSR_MBB) + if (get_timer (timeval) > TIMEOUT) + return -1; + + return 0; +} + +static __inline__ int +i2c_wait (int write) +{ + u32 csr; + ulong timeval = get_timer (0); + + do + { + csr = readl (I2CCSR); + + if (!(csr & MPC85xx_I2CSR_MIF)) + continue; + + writel (0x0, I2CCSR); + + if (csr & MPC85xx_I2CSR_MAL) + { + DEB(printf ("i2c_wait: MAL\n")); + return -1; + } + + if (!(csr & MPC85xx_I2CSR_MCF)) + { + DEB(printf ("i2c_wait: unfinished\n")); + return -1; + } + + if (write == I2C_WRITE && (csr & MPC85xx_I2CSR_RXAK)) + { + DEB(printf ("i2c_wait: No RXACK\n")); + return -1; + } + + return 0; + } while (get_timer (timeval) < TIMEOUT); + + DEB(printf ("i2c_wait: timed out\n")); + return -1; +} + +static __inline__ int +i2c_write_addr (u8 dev, u8 dir, int rsta) +{ + writel (MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | MPC85xx_I2CCR_MTX | + (rsta?MPC85xx_I2CCR_RSTA:0), I2CCCR); + + writel ((dev << 1) | dir, I2CCDR); + + if (i2c_wait (I2C_WRITE) < 0) + return 0; + + return 1; +} + +static __inline__ int +__i2c_write (u8 *data, int length) +{ + int i; + + writel (MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | MPC85xx_I2CCR_MTX, I2CCCR); + + for (i=0; i < length; i++) + { + writel (data[i], I2CCDR); + + if (i2c_wait (I2C_WRITE) < 0) + break; + } + + return i; +} + +static __inline__ int +__i2c_read (u8 *data, int length) +{ + int i; + + writel (MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | + ((length == 1) ? MPC85xx_I2CCR_TXAK : 0), I2CCCR); + + /* dummy read */ + readl (I2CCDR); + + for (i=0; i < length; i++) + { + if (i2c_wait (I2C_READ) < 0) + break; + + /* Generate ack on last next to last byte */ + if (i == length - 2) + writel (MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | + MPC85xx_I2CCR_TXAK, I2CCCR); + + /* Generate stop on last byte */ + if (i == length - 1) + writel (MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_TXAK, I2CCCR); + + data[i] = readl (I2CCDR); + } + + return i; +} + +int +i2c_read (u8 dev, uint addr, int alen, u8 *data, int length) +{ + int i = 0; + u8 *a = (u8*)&addr; + + if (i2c_wait4bus () < 0) + goto exit; + + if (i2c_write_addr (dev, I2C_WRITE, 0) == 0) + goto exit; + + if (__i2c_write (&a[4 - alen], alen) != alen) + goto exit; + + if (i2c_write_addr (dev, I2C_READ, 1) == 0) + goto exit; + + i = __i2c_read (data, length); + + exit: + writel (MPC85xx_I2CCR_MEN, I2CCCR); + + return !(i == length); +} + +int +i2c_write (u8 dev, uint addr, int alen, u8 *data, int length) +{ + int i = 0; + u8 *a = (u8*)&addr; + + if (i2c_wait4bus () < 0) + goto exit; + + if (i2c_write_addr (dev, I2C_WRITE, 0) == 0) + goto exit; + + if (__i2c_write (&a[4 - alen], alen) != alen) + goto exit; + + i = __i2c_write (data, length); + + exit: + writel (MPC85xx_I2CCR_MEN, I2CCCR); + + return !(i == length); +} + +int i2c_probe (uchar chip) +{ + int tmp; + + /* + * Try to read the first location of the chip. The underlying + * driver doesn't appear to support sending just the chip address + * and looking for an <ACK> back. + */ + udelay(10000); + return i2c_read (chip, 0, 1, (char *)&tmp, 1); +} + +uchar i2c_reg_read (uchar i2c_addr, uchar reg) +{ + char buf[1]; + + i2c_read (i2c_addr, reg, 1, buf, 1); + + return (buf[0]); +} + +void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val) +{ + i2c_write (i2c_addr, reg, 1, &val, 1); +} + +#endif /* CONFIG_HARD_I2C */ diff --git a/cpu/mpc85xx/interrupts.c b/cpu/mpc85xx/interrupts.c new file mode 100644 index 0000000000..745b3b2a4a --- /dev/null +++ b/cpu/mpc85xx/interrupts.c @@ -0,0 +1,138 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2002 (440 port) + * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com + * + * (C) Copyright 2003 Motorola Inc. (MPC85xx port) + * Xianghua Xiao (X.Xiao@motorola.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <watchdog.h> +#include <command.h> +#include <asm/processor.h> +#include <ppc_asm.tmpl> + +unsigned decrementer_count; /* count value for 1e6/HZ microseconds */ + +static __inline__ unsigned long get_msr(void) +{ + unsigned long msr; + + asm volatile("mfmsr %0" : "=r" (msr) :); + return msr; +} + +static __inline__ void set_msr(unsigned long msr) +{ + asm volatile("mtmsr %0" : : "r" (msr)); + asm volatile("isync"); +} + +void enable_interrupts (void) +{ + set_msr (get_msr() | MSR_EE); +} + +/* returns flag if MSR_EE was set before */ +int disable_interrupts (void) +{ + ulong msr = get_msr(); + set_msr (msr & ~MSR_EE); + return ((msr & MSR_EE) != 0); +} + +/* interrupt is not supported yet */ +int interrupt_init (void) +{ + return (0); +} + +/* + * Install and free a interrupt handler. Not implemented yet. + */ + +void +irq_install_handler(int vec, interrupt_handler_t *handler, void *arg) +{ + return; +} + +void +irq_free_handler(int vec) +{ + return; +} + +/****************************************************************************/ + + +volatile ulong timestamp = 0; + +/* + * timer_interrupt - gets called when the decrementer overflows, + * with interrupts disabled. + * Trivial implementation - no need to be really accurate. + */ +void timer_interrupt(struct pt_regs *regs) +{ + printf ("*** Timer Interrupt *** "); + timestamp++; + +#if defined(CONFIG_WATCHDOG) + if ((timestamp % 1000) == 0) + reset_85xx_watchdog(); +#endif /* CONFIG_WATCHDOG */ +} + +void reset_timer (void) +{ + timestamp = 0; +} + +ulong get_timer (ulong base) +{ + return (timestamp - base); +} + +void set_timer (ulong t) +{ + timestamp = t; +} + +#if (CONFIG_COMMANDS & CFG_CMD_IRQ) + +/******************************************************************************* + * + * irqinfo - print information about PCI devices,not implemented. + * + */ +int +do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + printf ("\nInterrupt-unsupported:\n"); + + return 0; +} + +#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */ diff --git a/cpu/mpc85xx/pci.c b/cpu/mpc85xx/pci.c new file mode 100644 index 0000000000..5732c29eb6 --- /dev/null +++ b/cpu/mpc85xx/pci.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2003 Motorola Inc. + * Xianghua Xiao (x.xiao@motorola.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * PCI Configuration space access support for MPC85xx PCI Bridge + */ +#include <common.h> +#include <asm/cpm_85xx.h> +#include <pci.h> + +#if defined(CONFIG_PCI) +/* + * Initialize PCI Devices, report devices found. + */ +#ifndef CONFIG_PCI_PNP +static struct pci_config_table pci_mpc85xxads_config_table[] = { + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_IDSEL_NUMBER, PCI_ANY_ID, + pci_cfgfunc_config_device, { PCI_ENET0_IOADDR, + PCI_ENET0_MEMADDR, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER }}, + { } +}; +#endif + +struct pci_controller local_hose = { +#ifndef CONFIG_PCI_PNP + config_table: pci_mpc85xxads_config_table, +#endif +}; + +void pci_init_board(void) +{ + struct pci_controller* hose = (struct pci_controller *)&local_hose; + volatile immap_t *immap = (immap_t *)CFG_CCSRBAR; + volatile ccsr_pcix_t *pcix = &immap->im_pcix; + + u16 reg16; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + pci_set_region(hose->regions + 0, + CFG_PCI_MEM_BASE, + CFG_PCI_MEM_PHYS, + (CFG_PCI_MEM_SIZE/2), + PCI_REGION_MEM); + + pci_set_region(hose->regions + 1, + (CFG_PCI_MEM_BASE+0x08000000), + (CFG_PCI_MEM_PHYS+0x08000000), + 0x1000000, /* 16M */ + PCI_REGION_IO); + + hose->region_count = 2; + + pci_setup_indirect(hose, + (CFG_IMMR+0x8000), + (CFG_IMMR+0x8004)); + + pci_register_hose(hose); + + hose->last_busno = pci_hose_scan(hose); + + pci_read_config_word (PCI_BDF(0,0,0), PCI_COMMAND, ®16); + reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + pci_write_config_word(PCI_BDF(0,0,0), PCI_COMMAND, reg16); + + /* Clear non-reserved bits in status register */ + pci_write_config_word(PCI_BDF(0,0,0), PCI_STATUS, 0xffff); + pci_write_config_byte(PCI_BDF(0,0,0), PCI_LATENCY_TIMER,0x80); + + pcix->potar1 = (CFG_PCI_MEM_BASE >> 12) & 0x000fffff; + pcix->potear1 = 0x00000000; + pcix->powbar1 = (CFG_PCI_MEM_BASE >> 12) & 0x000fffff; + pcix->powbear1 = 0x00000000; + pcix->powar1 = 0x8004401a; /* 128M MEM space */ + pcix->potar2 = ((CFG_PCI_MEM_BASE + 0x08000000) >> 12) & 0x000fffff; + pcix->potear2 = 0x00000000; + pcix->powbar2 = ((CFG_PCI_MEM_BASE + 0x08000000) >> 12) && 0x000fffff; + pcix->powbear2 = 0x00000000; + pcix->powar2 = 0x80088017; /* 16M IO space */ + pcix->pitar1 = 0x00000000; + pcix->piwbar1 = 0x00000000; + pcix->piwar1 = 0xa0F5501f; + +} +#endif /* CONFIG_PCI */ diff --git a/cpu/mpc85xx/resetvec.S b/cpu/mpc85xx/resetvec.S new file mode 100644 index 0000000000..29555d4a00 --- /dev/null +++ b/cpu/mpc85xx/resetvec.S @@ -0,0 +1,2 @@ + .section .resetvec,"ax" + b _start_e500 diff --git a/cpu/mpc85xx/serial_scc.c b/cpu/mpc85xx/serial_scc.c new file mode 100644 index 0000000000..ea82761465 --- /dev/null +++ b/cpu/mpc85xx/serial_scc.c @@ -0,0 +1,274 @@ +/* + * (C) Copyright 2003 Motorola Inc. + * Xianghua Xiao (X.Xiao@motorola.com) + * Modified based on 8260 for 8560. + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00. + */ + +/* + * Minimal serial functions needed to use one of the SCC ports + * as serial console interface. + */ + +#include <common.h> +#include <asm/cpm_85xx.h> + +#if defined(CONFIG_MPC8560) +#if defined(CONFIG_CONS_ON_SCC) + +#if CONFIG_CONS_INDEX == 1 /* Console on SCC1 */ + +#define SCC_INDEX 0 +#define PROFF_SCC PROFF_SCC1 +#define CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\ + CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1) +#define CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK + +#elif CONFIG_CONS_INDEX == 2 /* Console on SCC2 */ + +#define SCC_INDEX 1 +#define PROFF_SCC PROFF_SCC2 +#define CMXSCR_MASK (CMXSCR_GR2|CMXSCR_SC2|\ + CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2) +#define CPM_CR_SCC_PAGE CPM_CR_SCC2_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC2_SBLOCK + +#elif CONFIG_CONS_INDEX == 3 /* Console on SCC3 */ + +#define SCC_INDEX 2 +#define PROFF_SCC PROFF_SCC3 +#define CMXSCR_MASK (CMXSCR_GR3|CMXSCR_SC3|\ + CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3) +#define CPM_CR_SCC_PAGE CPM_CR_SCC3_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC3_SBLOCK + +#elif CONFIG_CONS_INDEX == 4 /* Console on SCC4 */ + +#define SCC_INDEX 3 +#define PROFF_SCC PROFF_SCC4 +#define CMXSCR_MASK (CMXSCR_GR4|CMXSCR_SC4|\ + CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4) +#define CPM_CR_SCC_PAGE CPM_CR_SCC4_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC4_SBLOCK + +#else + +#error "console not correctly defined" + +#endif + +int serial_init (void) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + volatile ccsr_cpm_scc_t *sp; + volatile scc_uart_t *up; + volatile cbd_t *tbdf, *rbdf; + volatile ccsr_cpm_cp_t *cp = &(im->im_cpm.im_cpm_cp); + uint dpaddr; + + /* initialize pointers to SCC */ + + sp = (ccsr_cpm_scc_t *) &(im->im_cpm.im_cpm_scc[SCC_INDEX]); + up = (scc_uart_t *)&(im->im_cpm.im_dprambase[PROFF_SCC]); + + /* Disable transmitter/receiver. + */ + sp->gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* put the SCC channel into NMSI (non multiplexd serial interface) + * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15). + */ + im->im_cpm.im_cpm_mux.cmxscr = \ + (im->im_cpm.im_cpm_mux.cmxscr&~CMXSCR_MASK)|CMXSCR_VALUE; + + /* Set up the baud rate generator. + */ + serial_setbrg (); + + /* Allocate space for two buffer descriptors in the DP ram. + * damm: allocating space after the two buffers for rx/tx data + */ + + dpaddr = m8560_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&(im->im_cpm.im_dprambase[dpaddr]); + rbdf->cbd_bufaddr = (uint) (rbdf+2); + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; + tbdf->cbd_sc = BD_SC_WRAP; + + /* Set up the uart parameters in the parameter ram. + */ + up->scc_genscc.scc_rbase = dpaddr; + up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t); + up->scc_genscc.scc_rfcr = CPMFCR_EB; + up->scc_genscc.scc_tfcr = CPMFCR_EB; + up->scc_genscc.scc_mrblr = 1; + up->scc_maxidl = 0; + up->scc_brkcr = 1; + up->scc_parec = 0; + up->scc_frmec = 0; + up->scc_nosec = 0; + up->scc_brkec = 0; + up->scc_uaddr1 = 0; + up->scc_uaddr2 = 0; + up->scc_toseq = 0; + up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000; + up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000; + up->scc_rccm = 0xc0ff; + + /* Mask all interrupts and remove anything pending. + */ + sp->sccm = 0; + sp->scce = 0xffff; + + /* Set 8 bit FIFO, 16 bit oversampling and UART mode. + */ + sp->gsmrh = SCC_GSMRH_RFW; /* 8 bit FIFO */ + sp->gsmrl = \ + SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART; + + /* Set CTS no flow control, 1 stop bit, 8 bit character length, + * normal async UART mode, no parity + */ + sp->psmr = SCU_PSMR_CL; + + /* execute the "Init Rx and Tx params" CP command. + */ + + while (cp->cpcr & CPM_CR_FLG) /* wait if cp is busy */ + ; + + cp->cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK, + 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; + + while (cp->cpcr & CPM_CR_FLG) /* wait if cp is busy */ + ; + + /* Enable transmitter/receiver. + */ + sp->gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT; + + return (0); +} + +void +serial_setbrg (void) +{ + DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_CONS_USE_EXTC) + m8560_cpm_extcbrg(SCC_INDEX, gd->baudrate, + CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL); +#else + m8560_cpm_setbrg(SCC_INDEX, gd->baudrate); +#endif +} + +void +serial_putc(const char c) +{ + volatile scc_uart_t *up; + volatile cbd_t *tbdf; + volatile immap_t *im; + + if (c == '\n') + serial_putc ('\r'); + + im = (immap_t *)CFG_IMMR; + up = (scc_uart_t *)&(im->im_cpm.im_dprambase[PROFF_SCC]); + tbdf = (cbd_t *)&(im->im_cpm.im_dprambase[up->scc_genscc.scc_tbase]); + + /* Wait for last character to go. + */ + while (tbdf->cbd_sc & BD_SC_READY) + ; + + /* Load the character into the transmit buffer. + */ + *(volatile char *)tbdf->cbd_bufaddr = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +int +serial_getc(void) +{ + volatile cbd_t *rbdf; + volatile scc_uart_t *up; + volatile immap_t *im; + unsigned char c; + + im = (immap_t *)CFG_IMMR; + up = (scc_uart_t *)&(im->im_cpm.im_dprambase[PROFF_SCC]); + rbdf = (cbd_t *)&(im->im_cpm.im_dprambase[up->scc_genscc.scc_rbase]); + + /* Wait for character to show up. + */ + while (rbdf->cbd_sc & BD_SC_EMPTY) + ; + + /* Grab the char and clear the buffer again. + */ + c = *(volatile unsigned char *)rbdf->cbd_bufaddr; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return (c); +} + +int +serial_tstc() +{ + volatile cbd_t *rbdf; + volatile scc_uart_t *up; + volatile immap_t *im; + + im = (immap_t *)CFG_IMMR; + up = (scc_uart_t *)&(im->im_cpm.im_dprambase[PROFF_SCC]); + rbdf = (cbd_t *)&(im->im_cpm.im_dprambase[up->scc_genscc.scc_rbase]); + + return ((rbdf->cbd_sc & BD_SC_EMPTY) == 0); +} + +#endif /* CONFIG_CONS_ON_SCC */ + +#endif /* CONFIG_MPC8560 */ diff --git a/cpu/mpc85xx/spd_sdram.c b/cpu/mpc85xx/spd_sdram.c new file mode 100644 index 0000000000..ccd06e96a5 --- /dev/null +++ b/cpu/mpc85xx/spd_sdram.c @@ -0,0 +1,308 @@ +/* + * (C) Copyright 2003 Motorola Inc. + * Xianghua Xiao (X.Xiao@motorola.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/processor.h> +#include <i2c.h> +#include <spd.h> +#include <asm/mmu.h> + +#ifdef CONFIG_SPD_EEPROM + +#undef DEBUG + +#if defined(DEBUG) +#define DEB(x) x +#else +#define DEB(x) +#endif + +#define ns2clk(ns) ((ns) / (2000000000 /get_bus_freq(0) + 1)) + +long int spd_sdram(void) { + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile ccsr_ddr_t *ddr = &immap->im_ddr; + volatile ccsr_local_ecm_t *ecm = &immap->im_local_ecm; + spd_eeprom_t spd; + unsigned int memsize,tmp,tmp1,tmp2; + unsigned char caslat; + + i2c_read (SPD_EEPROM_ADDRESS, 0, 1, (uchar *) & spd, sizeof (spd)); + + if ( spd.nrows > 2 ) { + printf("DDR:Only two chip selects are supported on ADS.\n"); + return 0; + } + + if ( spd.nrow_addr < 12 || spd.nrow_addr > 14 || spd.ncol_addr < 8 || spd.ncol_addr > 11) { + printf("DDR:Row or Col number unsupported.\n"); + return 0; + } + + ddr->cs0_bnds = ((spd.row_dens>>2) - 1); + ddr->cs0_config = ( 1<<31 | (spd.nrow_addr-12)<<8 | (spd.ncol_addr-8) ); + DEB(printf("\n")); + DEB(printf("cs0_bnds = 0x%08x\n",ddr->cs0_bnds)); + DEB(printf("cs0_config = 0x%08x\n",ddr->cs0_config)); + if ( spd.nrows == 2 ) { + ddr->cs1_bnds = ((spd.row_dens<<14) | ((spd.row_dens>>1) - 1)); + ddr->cs1_config = ( 1<<31 | (spd.nrow_addr-12)<<8 | (spd.ncol_addr-8) ); + DEB(printf("cs1_bnds = 0x%08x\n",ddr->cs1_bnds)); + DEB(printf("cs1_config = 0x%08x\n",ddr->cs1_config)); + } + + memsize = spd.nrows * (4 * spd.row_dens); + if( spd.mem_type == 0x07 ) { + printf("DDR module detected, total size:%dMB.\n",memsize); + } else { + printf("No DDR module found!\n"); + return 0; + } + + switch(memsize) { + case 16: + tmp = 7; /* TLB size */ + tmp1 = 1; /* TLB entry number */ + tmp2 = 23; /* Local Access Window size */ + break; + case 32: + tmp = 7; + tmp1 = 2; + tmp2 = 24; + break; + case 64: + tmp = 8; + tmp1 = 1; + tmp2 = 25; + break; + case 128: + tmp = 8; + tmp1 = 2; + tmp2 = 26; + break; + case 256: + tmp = 9; + tmp1 = 1; + tmp2 = 27; + break; + case 512: + tmp = 9; + tmp1 = 2; + tmp2 = 28; + break; + case 1024: + tmp = 10; + tmp1 = 1; + tmp2 = 29; + break; + default: + printf("DDR:we only added support 16M,32M,64M,128M,256M,512M and 1G DDR I.\n"); + return 0; + break; + } + + /* configure DDR TLB to TLB1 Entry 4,5 */ + mtspr(MAS0, TLB1_MAS0(1,4,0)); + mtspr(MAS1, TLB1_MAS1(1,1,0,0,tmp)); + mtspr(MAS2, TLB1_MAS2(((CFG_DDR_SDRAM_BASE>>12) & 0xfffff),0,0,0,0,0,0,0,0)); + mtspr(MAS3, TLB1_MAS3(((CFG_DDR_SDRAM_BASE>>12) & 0xfffff),0,0,0,0,0,1,0,1,0,1)); + asm volatile("isync;msync;tlbwe;isync"); + DEB(printf("DDR:MAS0=0x%08x\n",TLB1_MAS0(1,4,0))); + DEB(printf("DDR:MAS1=0x%08x\n",TLB1_MAS1(1,1,0,0,tmp))); + DEB(printf("DDR:MAS2=0x%08x\n",TLB1_MAS2(((CFG_DDR_SDRAM_BASE>>12) \ + & 0xfffff),0,0,0,0,0,0,0,0))); + DEB(printf("DDR:MAS3=0x%08x\n",TLB1_MAS3(((CFG_DDR_SDRAM_BASE>>12) \ + & 0xfffff),0,0,0,0,0,1,0,1,0,1))); + + if(tmp1 == 2) { + mtspr(MAS0, TLB1_MAS0(1,5,0)); + mtspr(MAS1, TLB1_MAS1(1,1,0,0,tmp)); + mtspr(MAS2, TLB1_MAS2((((CFG_DDR_SDRAM_BASE+(memsize*1024*1024)/2)>>12) \ + & 0xfffff),0,0,0,0,0,0,0,0)); + mtspr(MAS3, TLB1_MAS3((((CFG_DDR_SDRAM_BASE+(memsize*1024*1024)/2)>>12) \ + & 0xfffff),0,0,0,0,0,1,0,1,0,1)); + asm volatile("isync;msync;tlbwe;isync"); + DEB(printf("DDR:MAS0=0x%08x\n",TLB1_MAS0(1,5,0))); + DEB(printf("DDR:MAS1=0x%08x\n",TLB1_MAS1(1,1,0,0,tmp))); + DEB(printf("DDR:MAS2=0x%08x\n",TLB1_MAS2((((CFG_DDR_SDRAM_BASE \ + +(memsize*1024*1024)/2)>>12) & 0xfffff),0,0,0,0,0,0,0,0))); + DEB(printf("DDR:MAS3=0x%08x\n",TLB1_MAS3((((CFG_DDR_SDRAM_BASE \ + +(memsize*1024*1024)/2)>>12) & 0xfffff),0,0,0,0,0,1,0,1,0,1))); + } + +#if defined(CONFIG_RAM_AS_FLASH) + ecm->lawbar2 = ((CFG_DDR_SDRAM_BASE>>12) & 0xfffff); + ecm->lawar2 = (LAWAR_EN | LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & tmp2)); + DEB(printf("DDR:LAWBAR2=0x%08x\n",ecm->lawbar2)); + DEB(printf("DDR:LARAR2=0x%08x\n",ecm->lawar2)); +#else + ecm->lawbar1 = ((CFG_DDR_SDRAM_BASE>>12) & 0xfffff); + ecm->lawar1 = (LAWAR_EN | LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & tmp2)); + DEB(printf("DDR:LAWBAR1=0x%08x\n",ecm->lawbar1)); + DEB(printf("DDR:LARAR1=0x%08x\n",ecm->lawar1)); +#endif + + tmp = 20000/(((spd.clk_cycle & 0xF0) >> 4) * 10 + (spd.clk_cycle & 0x0f)); + DEB(printf("DDR:Module maximum data rate is: %dMhz\n",tmp)); + + /* find the largest CAS */ + if(spd.cas_lat & 0x40) { + caslat = 7; + } else if (spd.cas_lat & 0x20) { + caslat = 6; + } else if (spd.cas_lat & 0x10) { + caslat = 5; + } else if (spd.cas_lat & 0x08) { + caslat = 4; + } else if (spd.cas_lat & 0x04) { + caslat = 3; + } else if (spd.cas_lat & 0x02) { + caslat = 2; + } else if (spd.cas_lat & 0x01) { + caslat = 1; + } else { + printf("DDR:no valid CAS Latency information.\n"); + return 0; + } + + tmp1 = get_bus_freq(0)/1000000; + if(tmp1<230 && tmp1>=90 && tmp>=230) { /* 90~230 range, treated as DDR 200 */ + if(spd.clk_cycle3 == 0xa0) caslat -= 2; + else if(spd.clk_cycle2 == 0xa0) caslat--; + } else if(tmp1<280 && tmp1>=230 && tmp>=280) { /* 230-280 range, treated as DDR 266 */ + if(spd.clk_cycle3 == 0x75) caslat -= 2; + else if(spd.clk_cycle2 == 0x75) caslat--; + } else if(tmp1<350 && tmp1>=280 && tmp>=350) { /* 280~350 range, treated as DDR 333 */ + if(spd.clk_cycle3 == 0x60) caslat -= 2; + else if(spd.clk_cycle2 == 0x60) caslat--; + } else if(tmp1<90 || tmp1 >=350) { /* DDR rate out-of-range */ + printf("DDR:platform frequency is not fit for DDR rate\n"); + return 0; + } + + /* note: caslat must also be programmed into ddr->sdram_mode register */ + /* note: WRREC(Twr) and WRTORD(Twtr) are not in SPD,use conservative value here */ +#if 1 + ddr->timing_cfg_1 = (((ns2clk(spd.trp/4) & 0x07) << 28 ) | \ + ((ns2clk(spd.tras) & 0x0f ) << 24 ) | \ + ((ns2clk(spd.trcd/4) & 0x07) << 20 ) | \ + ((caslat & 0x07)<< 16 ) | \ + (((ns2clk(spd.sset[6]) - 8) & 0x0f) << 12 ) | \ + ( 0x300 ) | \ + ((ns2clk(spd.trrd/4) & 0x07) << 4) | 1); +#else + ddr->timing_cfg_1 = 0x37344321; + caslat = 4; +#endif + DEB(printf("DDR:timing_cfg_1=0x%08x\n",ddr->timing_cfg_1)); + + /* note: hand-coded value for timing_cfg_2, see Errata DDR1*/ +#if defined(CONFIG_MPC85xx_REV1) + ddr->timing_cfg_2 = 0x00000800; +#endif + DEB(printf("DDR:timing_cfg_2=0x%08x\n",ddr->timing_cfg_2)); + + /* only DDR I is supported, DDR I and II have different mode-register-set definition */ + /* burst length is always 4 */ + switch(caslat) { + case 2: + ddr->sdram_mode = 0x52; /* 1.5 */ + break; + case 3: + ddr->sdram_mode = 0x22; /* 2.0 */ + break; + case 4: + ddr->sdram_mode = 0x62; /* 2.5 */ + break; + case 5: + ddr->sdram_mode = 0x32; /* 3.0 */ + break; + default: + printf("DDR:only CAS Latency 1.5,2.0,2.5,3.0 is supported.\n"); + return 0; + } + DEB(printf("DDR:sdram_mode=0x%08x\n",ddr->sdram_mode)); + + switch(spd.refresh) { + case 0x00: + case 0x80: + tmp = ns2clk(15625); + break; + case 0x01: + case 0x81: + tmp = ns2clk(3900); + break; + case 0x02: + case 0x82: + tmp = ns2clk(7800); + break; + case 0x03: + case 0x83: + tmp = ns2clk(31300); + break; + case 0x04: + case 0x84: + tmp = ns2clk(62500); + break; + case 0x05: + case 0x85: + tmp = ns2clk(125000); + break; + default: + tmp = 0x512; + break; + } + + /* set BSTOPRE to 0x100 for page mode, if auto-charge is used, set BSTOPRE = 0 */ + ddr->sdram_interval = ((tmp & 0x3fff) << 16) | 0x100; + DEB(printf("DDR:sdram_interval=0x%08x\n",ddr->sdram_interval)); + + /* is this an ECC DDR chip? */ +#if defined(CONFIG_DDR_ECC) + if(spd.config == 0x02) { + ddr->err_disable = 0x0000000d; + ddr->err_sbe = 0x00ff0000; + } + DEB(printf("DDR:err_disable=0x%08x\n",ddr->err_disable)); + DEB(printf("DDR:err_sbe=0x%08x\n",ddr->err_sbe)); +#endif + asm("sync;isync;msync"); + + udelay(500); + + /* registered or unbuffered? */ +#if defined(CONFIG_DDR_ECC) + ddr->sdram_cfg = (spd.config == 0x02)?0x20000000:0x0; +#endif + ddr->sdram_cfg = 0xc2000000|((spd.mod_attr == 0x20) ? 0x0 : \ + ((spd.mod_attr == 0x26) ? 0x10000000:0x0)); + asm("sync;isync;msync"); + + udelay(500); + + DEB(printf("DDR:sdram_cfg=0x%08x\n",ddr->sdram_cfg)); + + return (memsize*1024*1024); +} + +#endif /* CONFIG_SPD_EEPROM */ diff --git a/cpu/mpc85xx/speed.c b/cpu/mpc85xx/speed.c new file mode 100644 index 0000000000..a720cff3b2 --- /dev/null +++ b/cpu/mpc85xx/speed.c @@ -0,0 +1,124 @@ +/* + * (C) Copyright 2003 Motorola Inc. + * Xianghua Xiao, (X.Xiao@motorola.com) + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <ppc_asm.tmpl> +#include <asm/processor.h> + +/* --------------------------------------------------------------- */ + +#define ONE_BILLION 1000000000 + +void get_sys_info (sys_info_t * sysInfo) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile ccsr_gur_t *gur = &immap->im_gur; + uint plat_ratio,e500_ratio; + + plat_ratio = (gur->porpllsr) & 0x0000003e; + plat_ratio >>= 1; + switch(plat_ratio) { + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x08: + case 0x09: + case 0x0a: + case 0x0c: + case 0x10: + sysInfo->freqSystemBus = plat_ratio * CONFIG_SYS_CLK_FREQ; + break; + default: + sysInfo->freqSystemBus = 0; + break; + } + + e500_ratio = (gur->porpllsr) & 0x003f0000; + e500_ratio >>= 16; + switch(e500_ratio) { + case 0x04: + sysInfo->freqProcessor = 2*sysInfo->freqSystemBus; + break; + case 0x05: + sysInfo->freqProcessor = 5*sysInfo->freqSystemBus/2; + break; + case 0x06: + sysInfo->freqProcessor = 3*sysInfo->freqSystemBus; + break; + case 0x07: + sysInfo->freqProcessor = 7*sysInfo->freqSystemBus/2; + break; + default: + sysInfo->freqProcessor = 0; + break; + } +} + +int get_clocks (void) +{ + DECLARE_GLOBAL_DATA_PTR; + sys_info_t sys_info; +#if defined(CONFIG_MPC8560) + volatile immap_t *immap = (immap_t *) CFG_IMMR; + uint sccr, dfbrg; + + /* set VCO = 4 * BRG */ + immap->im_cpm.im_cpm_intctl.sccr &= 0xfffffffc; + sccr = immap->im_cpm.im_cpm_intctl.sccr; + dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT; +#endif + get_sys_info (&sys_info); + gd->cpu_clk = sys_info.freqProcessor; + gd->bus_clk = sys_info.freqSystemBus; +#if defined(CONFIG_MPC8560) + gd->vco_out = 2*sys_info.freqSystemBus; + gd->cpm_clk = gd->vco_out / 2; + gd->scc_clk = gd->vco_out / 4; + gd->brg_clk = gd->vco_out / (1 << (2 * (dfbrg + 1))); +#endif + + if(gd->cpu_clk != 0) return (0); + else return (1); +} + + +/******************************************** + * get_bus_freq + * return system bus freq in Hz + *********************************************/ +ulong get_bus_freq (ulong dummy) +{ + ulong val; + + sys_info_t sys_info; + + get_sys_info (&sys_info); + val = sys_info.freqSystemBus; + + return val; +} diff --git a/cpu/mpc85xx/start.S b/cpu/mpc85xx/start.S new file mode 100644 index 0000000000..468923c998 --- /dev/null +++ b/cpu/mpc85xx/start.S @@ -0,0 +1,1156 @@ +/* + * Copyright (C) 2003 Motorola,Inc. + * Xianghua Xiao<X.Xiao@motorola.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* U-Boot Startup Code for Motorola 85xx PowerPC based Embedded Boards + * + * The processor starts at 0xfffffffc and the code is first executed in the + * last 4K page(0xfffff000-0xffffffff) in flash/rom. + * + */ + +#include <config.h> +#include <mpc85xx.h> +#include <version.h> + +#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */ + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +#include <asm/cache.h> +#include <asm/mmu.h> + +#ifndef CONFIG_IDENT_STRING +#define CONFIG_IDENT_STRING "" +#endif + +#undef MSR_KERNEL +#define MSR_KERNEL ( MSR_ME ) /* Machine Check */ + +/* + * Set up GOT: Global Offset Table + * + * Use r14 to access the GOT + */ + START_GOT + GOT_ENTRY(_GOT2_TABLE_) + GOT_ENTRY(_FIXUP_TABLE_) + + GOT_ENTRY(_start) + GOT_ENTRY(_start_of_vectors) + GOT_ENTRY(_end_of_vectors) + GOT_ENTRY(transfer_to_handler) + + GOT_ENTRY(__init_end) + GOT_ENTRY(_end) + GOT_ENTRY(__bss_start) + END_GOT + +/* + * e500 Startup -- after reset only the last 4KB of the effective + * address space is mapped in the MMU L2 TLB1 Entry0. The .bootpg + * section is located at THIS LAST page and basically does three + * things: clear some registers, set up exception tables and + * add more TLB entries for 'larger spaces'(e.g. the boot rom) to + * continue the boot procedure. + + * Once the boot rom is mapped by TLB entries we can proceed + * with normal startup. + * + */ + + .section .bootpg,"ax" + .globl _start_e500 + +_start_e500: +#if defined(CONFIG_MPC85xx_REV1) + li r0,0x2000 + mtspr 977,r0 +#endif + + /* Clear and set up some registers. Note: Some registers need strict + * synchronization by sync/mbar/msync/isync when being "mtspr". + * BookE: isync before PID,tlbivax,tlbwe + * BookE: isync after MSR,PID; msync_isync after tlbivax & tlbwe + * E500: msync,isync before L1CSR0 + * E500: isync after BBEAR,BBTAR,BUCSR,DBCR0,DBCR1,HID0,HID1,L1CSR0 + * L1CSR1, MAS[0,1,2,3,4,6],MMUCSR0, PID[0,1,2],SPEFCSR + */ + + /* invalidate d-cache */ + mfspr r0,L1CSR0 + ori r0,r0,0x0002 + msync + isync + mtspr L1CSR0,r0 + isync + + /* disable d-cache */ + li r0,0x0 + mtspr L1CSR0,r0 + isync + + /* invalidate i-cache */ + mfspr r0,L1CSR1 + ori r0,r0,0x0002 + mtspr L1CSR1,r0 + isync + + /* disable i-cache */ + li r0,0x0 + mtspr L1CSR1,r0 + isync + + /* clear registers */ + sync + li r0,0 + mtspr SRR0,r0 + mtspr SRR1,r0 + mtspr CSRR0,r0 + mtspr CSRR1,r0 + mtspr MCSRR0,r0 + mtspr MCSRR1,r0 + + mtspr ESR,r0 + mtspr MCSR,r0 + mtspr DEAR,r0 + + mtspr DBCR0,r0 + isync + mtspr DBCR1,r0 + isync + mtspr DBCR2,r0 + isync + mtspr IAC1,r0 + mtspr IAC2,r0 + mtspr DAC1,r0 + mtspr DAC2,r0 + + mfspr r1,DBSR + mtspr DBSR,r1 /* Clear all valid bits */ + + isync + mtspr PID0,r0 + isync + mtspr PID1,r0 + isync + mtspr PID2,r0 + isync + + mtspr TCR,r0 + + mtspr BUCSR,r0 /* disable branch prediction */ + isync + + mtspr HID0,r0 + isync + mtspr HID1,r0 + isync + + mtspr MAS4,r0 + isync + mtspr MAS6,r0 + isync + + /* Setup interrupt vectors */ + mtspr IVPR, r0 + + li r1,0x0100 + mtspr IVOR0,r1 /* 0: Critical input */ + li r1,0x0200 + mtspr IVOR1,r1 /* 1: Machine check */ + li r1,0x0300 + mtspr IVOR2,r1 /* 2: Data storage */ + li r1,0x0400 + mtspr IVOR3,r1 /* 3: Instruction storage */ + li r1,0x0500 + mtspr IVOR4,r1 /* 4: External interrupt */ + li r1,0x0600 + mtspr IVOR5,r1 /* 5: Alignment */ + li r1,0x0700 + mtspr IVOR6,r1 /* 6: Program check */ + li r1,0x0800 + mtspr IVOR7,r1 /* 7: floating point unavailable */ + li r1,0x0c00 + mtspr IVOR8,r1 /* 8: System call */ + /* 9: Auxiliary processor unavailable(unsupported) */ + li r1,0x1000 + mtspr IVOR10,r1 /* 10: Decrementer */ + li r1,0x1400 + mtspr IVOR13,r1 /* 13: Data TLB error */ + li r1,0x1300 + mtspr IVOR14,r1 /* 14: Instruction TLB error */ + li r1,0x2000 + mtspr IVOR15,r1 /* 15: Debug */ + + /* invalidate MMU L1/L2 */ + /* Note: before invalidate MMU L1/L2, we read TLB1 Entry 0 and then + * write it back immediately to fixup a bug(Errata CPU4) for this initial + * TLB1 entry 0,otherwise the TLB1 entry 0 will be invalidated. + */ +#if defined(CONFIG_MPC85xx_REV1) + lis r2,0x1000 + mtspr MAS0,r2 + tlbre + tlbwe + isync + li r2, 0x001e + mtspr MMUCSR0, r2 + isync +#endif + + /* After reset, CCSRBAR is located at CFG_CCSRBAR_DEFAULT, i.e. + * 0xff700000-0xff800000. We need add a TLB1 entry for this 1MB + * region before we can access any CCSR registers such as L2 + * registers, Local Access Registers,etc. We will also re-allocate + * CFG_CCSRBAR_DEFAULT to CFG_CCSRBAR immediately after TLB1 setup. + * + * Please refer to board-specif directory for TLB1 entry configuration. + * (e.g. board/<yourboard>/init.S) + * + */ + bl tlb1_entry + mr r5,r0 + li r1,0x000f /* max 16 TLB1 entries */ + mtctr r1 + lwzu r4,0(r5) /* how many TLB1 entries we actually use */ + +0: cmpwi r4,0 + beq 1f + lwzu r0,4(r5) + lwzu r1,4(r5) + lwzu r2,4(r5) + lwzu r3,4(r5) + mtspr MAS0,r0 + mtspr MAS1,r1 + mtspr MAS2,r2 + mtspr MAS3,r3 + isync + msync + tlbwe + isync + addi r4,r4,-1 + bdnz 0b + +1: +#if (CFG_CCSRBAR_DEFAULT != CFG_CCSRBAR) + /* Special sequence needed to update CCSRBAR itself */ + lis r4, CFG_CCSRBAR_DEFAULT@h + ori r4, r4, CFG_CCSRBAR_DEFAULT@l + + lis r5, CFG_CCSRBAR@h + ori r5, r5, CFG_CCSRBAR@l + srwi r6,r5,12 + stw r6, 0(r4) + isync + + lis r5, 0xffff + ori r5,r5,0xf000 + lwz r5, 0(r5) + isync + + lis r3, CFG_CCSRBAR@h + lwz r5, CFG_CCSRBAR@l(r3) + isync +#endif + + /* invalidate all TLB0 entries */ + li r3,4 + li r4,0 + tlbivax r4,r3 +#if defined(CONFIG_MPC85xx_REV1) /* Errata CPU6 */ + nop +#endif + + /* set up local access windows, defined at board/<boardname>/init.S */ + lis r7,CFG_CCSRBAR@h + ori r7,r7,CFG_CCSRBAR@l + + bl law_entry + mr r6,r0 +#if defined(CONFIG_RAM_AS_FLASH) + li r1,0x0006 +#else + li r1,0x0007 /*we have 8 LAWs, but reseve one for boot-over-rio-or-pci */ +#endif + mtctr r1 + lwzu r5,0(r6) /* how many windows we actually use */ + +#if defined(CONFIG_RAM_AS_FLASH) + li r2,0x0c48 + li r1,0x0c50 +#else + li r2,0x0c28 /* the first pair is reserved for boot-over-rio-or-pci */ + li r1,0x0c30 +#endif + +0: cmpwi r5,0 + beq 1f + lwzu r4,4(r6) + lwzu r3,4(r6) + stwx r4,r7,r2 + stwx r3,r7,r1 + addi r5,r5,-1 + addi r2,r2,0x0020 + addi r1,r1,0x0020 + bdnz 0b + + /* Jump out the last 4K page and continue to 'normal' start */ +1: bl 3f + b _start + +3: li r0,0 + mtspr SRR1,r0 /* Keep things disabled for now */ + mflr r1 + mtspr SRR0,r1 + rfi + +/* + * r3 - 1st arg to board_init(): IMMP pointer + * r4 - 2nd arg to board_init(): boot flag + */ + .text + .long 0x27051956 /* U-BOOT Magic Number */ + .globl version_string +version_string: + .ascii U_BOOT_VERSION + .ascii " (", __DATE__, " - ", __TIME__, ")" + .ascii CONFIG_IDENT_STRING, "\0" + + . = EXC_OFF_SYS_RESET + .globl _start +_start: + /* Clear and set up some registers. */ + li r0,0x0000 + lis r1,0xffff + mtspr DEC,r0 /* prevent dec exceptions */ + mttbl r0 /* prevent fit & wdt exceptions */ + mttbu r0 + mtspr TSR,r1 /* clear all timer exception status */ + mtspr TCR,r0 /* disable all */ + mtspr ESR,r0 /* clear exception syndrome register */ + mtspr MCSR,r0 /* machine check syndrome register */ + mtxer r0 /* clear integer exception register */ + lis r1,0x0002 /* set CE bit (Critical Exceptions) */ + ori r1,r1,0x1200 /* set ME/DE bit */ + mtmsr r1 /* change MSR */ + isync + + /* Enable Time Base and Select Time Base Clock */ + li r0,0x4000 /* time base is processor clock */ + mtspr HID0,r0 + isync + +#if defined(CONFIG_ADDR_STREAMING) + li r0,0x2000 + mtspr HID1,r0 + isync +#endif + + /* Enable Branch Prediction */ +#if defined(CONFIG_BTB) + li r0,0x201 /* BBFI = 1, BPEN = 1 */ + mtspr BUCSR,r0 + isync +#endif + +#if defined(CFG_INIT_DBCR) + lis r1,0xffff + ori r1,r1,0xffff + mtspr dbsr,r1 /* Clear all status bits */ + lis r0,CFG_INIT_DBCR@h /* DBCR0[IDM] must be set */ + ori r0,r0,CFG_INIT_DBCR@l + mtspr dbcr0,r0 + isync +#endif + +/* L1 DCache is used for initial RAM */ + mfspr r2, L1CSR0 + ori r2, r2, 0x0003 + oris r2, r2, 0x0001 + msync + isync + mtspr L1CSR0, r2 /* enable/invalidate L1 Dcache */ + isync + + /* Allocate Initial RAM in data cache. + */ + lis r3, CFG_INIT_RAM_ADDR@h + ori r3, r3, CFG_INIT_RAM_ADDR@l + li r2, 512 /* 512*32=16K */ + mtctr r2 + li r0, 0 +1: + dcbz r0, r3 + dcbtls 0,r0, r3 + addi r3, r3, 32 + bdnz 1b + +#ifndef CFG_RAMBOOT + /* Calculate absolute address in FLASH and jump there */ + /*--------------------------------------------------------------*/ + lis r3, CFG_MONITOR_BASE@h + ori r3, r3, CFG_MONITOR_BASE@l + addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET + mtlr r3 + blr + +in_flash: +#endif /* CFG_RAMBOOT */ + + /* Setup the stack in initial RAM,could be L2-as-SRAM or L1 dcache*/ + lis r1,CFG_INIT_RAM_ADDR@h + ori r1,r1,CFG_INIT_SP_OFFSET@l + + li r0,0 + stwu r0,-4(r1) + stwu r0,-4(r1) /* Terminate call chain */ + + stwu r1,-8(r1) /* Save back chain and move SP */ + lis r0,RESET_VECTOR@h /* Address of reset vector */ + ori r0,r0, RESET_VECTOR@l + stwu r1,-8(r1) /* Save back chain and move SP */ + stw r0,+12(r1) /* Save return addr (underflow vect) */ + + GET_GOT + bl cpu_init_f + bl icache_enable + bl board_init_f + sync + + +/* --FIXME-- machine check with MCSRRn and rfmci */ + + .globl _start_of_vectors +_start_of_vectors: +#if 0 +/* Critical input. */ + CRIT_EXCEPTION(0x0100, CritcalInput, CritcalInputException) +#endif +/* Machine check --FIXME-- Should be MACH_EXCEPTION */ + CRIT_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + +/* Data Storage exception. */ + STD_EXCEPTION(0x0300, DataStorage, UnknownException) + +/* Instruction Storage exception. */ + STD_EXCEPTION(0x0400, InstStorage, UnknownException) + +/* External Interrupt exception. */ + STD_EXCEPTION(0x0500, ExtInterrupt, UnknownException) + +/* Alignment exception. */ + . = 0x0600 +Alignment: + EXCEPTION_PROLOG + mfspr r4,DAR + stw r4,_DAR(r21) + mfspr r5,DSISR + stw r5,_DSISR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + lwz r6,GOT(transfer_to_handler) + mtlr r6 + blrl +.L_Alignment: + .long AlignmentException - _start + EXC_OFF_SYS_RESET + .long int_return - _start + EXC_OFF_SYS_RESET + +/* Program check exception */ + . = 0x0700 +ProgramCheck: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + lwz r6,GOT(transfer_to_handler) + mtlr r6 + blrl +.L_ProgramCheck: + .long ProgramCheckException - _start + EXC_OFF_SYS_RESET + .long int_return - _start + EXC_OFF_SYS_RESET + + /* No FPU on MPC85xx. This exception is not supposed to happen. + */ + STD_EXCEPTION(0x0800, FPUnavailable, UnknownException) + STD_EXCEPTION(0x0900, Decrementer, timer_interrupt) + STD_EXCEPTION(0x0a00, Trap_0a, UnknownException) + STD_EXCEPTION(0x0b00, Trap_0b, UnknownException) + + . = 0x0c00 +/* + * r0 - SYSCALL number + * r3-... arguments + */ +SystemCall: + addis r11,r0,0 /* get functions table addr */ + ori r11,r11,0 /* Note: this code is patched in trap_init */ + addis r12,r0,0 /* get number of functions */ + ori r12,r12,0 + + cmplw 0, r0, r12 + bge 1f + + rlwinm r0,r0,2,0,31 /* fn_addr = fn_tbl[r0] */ + add r11,r11,r0 + lwz r11,0(r11) + + li r20,0xd00-4 /* Get stack pointer */ + lwz r12,0(r20) + subi r12,r12,12 /* Adjust stack pointer */ + li r0,0xc00+_end_back-SystemCall + cmplw 0, r0, r12 /* Check stack overflow */ + bgt 1f + stw r12,0(r20) + + mflr r0 + stw r0,0(r12) + mfspr r0,SRR0 + stw r0,4(r12) + mfspr r0,SRR1 + stw r0,8(r12) + + li r12,0xc00+_back-SystemCall + mtlr r12 + mtspr SRR0,r11 + +1: SYNC + rfi +_back: + + mfmsr r11 /* Disable interrupts */ + li r12,0 + ori r12,r12,MSR_EE + andc r11,r11,r12 + SYNC /* Some chip revs need this... */ + mtmsr r11 + SYNC + + li r12,0xd00-4 /* restore regs */ + lwz r12,0(r12) + + lwz r11,0(r12) + mtlr r11 + lwz r11,4(r12) + mtspr SRR0,r11 + lwz r11,8(r12) + mtspr SRR1,r11 + + addi r12,r12,12 /* Adjust stack pointer */ + li r20,0xd00-4 + stw r12,0(r20) + + SYNC + rfi +_end_back: + + STD_EXCEPTION(0xd00, SingleStep, UnknownException) + + STD_EXCEPTION(0xe00, Trap_0e, UnknownException) + STD_EXCEPTION(0xf00, Trap_0f, UnknownException) + + STD_EXCEPTION(0x1000, PIT, PITException) + + STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException) + STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException) + STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException) + STD_EXCEPTION(0x1400, DataTLBError, UnknownException) + + STD_EXCEPTION(0x1500, Reserved5, UnknownException) + STD_EXCEPTION(0x1600, Reserved6, UnknownException) + STD_EXCEPTION(0x1700, Reserved7, UnknownException) + STD_EXCEPTION(0x1800, Reserved8, UnknownException) + STD_EXCEPTION(0x1900, Reserved9, UnknownException) + STD_EXCEPTION(0x1a00, ReservedA, UnknownException) + STD_EXCEPTION(0x1b00, ReservedB, UnknownException) + + STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException) + STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException) + STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException) + STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException) + + CRIT_EXCEPTION(0x2000, DebugBreakpoint, DebugException ) + + .globl _end_of_vectors +_end_of_vectors: + + + . = 0x2100 + +/* + * This code finishes saving the registers to the exception frame + * and jumps to the appropriate handler for the exception. + * Register r21 is pointer into trap frame, r1 has new stack pointer. + */ + .globl transfer_to_handler +transfer_to_handler: + stw r22,_NIP(r21) + lis r22,MSR_POW@h + andc r23,r23,r22 + stw r23,_MSR(r21) + SAVE_GPR(7, r21) + SAVE_4GPRS(8, r21) + SAVE_8GPRS(12, r21) + SAVE_8GPRS(24, r21) + + mflr r23 + andi. r24,r23,0x3f00 /* get vector offset */ + stw r24,TRAP(r21) + li r22,0 + stw r22,RESULT(r21) + mtspr SPRG2,r22 /* r1 is now kernel sp */ + + lwz r24,0(r23) /* virtual address of handler */ + lwz r23,4(r23) /* where to go when done */ + mtspr SRR0,r24 + mtspr SRR1,r20 + mtlr r23 + SYNC + rfi /* jump to handler, enable MMU */ + +int_return: + mfmsr r28 /* Disable interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r28,r28,r4 + SYNC /* Some chip revs need this... */ + mtmsr r28 + SYNC + lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + REST_10GPRS(3, r1) + REST_10GPRS(13, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SRR0,r2 + mtspr SRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfi + +crit_return: + mfmsr r28 /* Disable interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r28,r28,r4 + SYNC /* Some chip revs need this... */ + mtmsr r28 + SYNC + lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + REST_10GPRS(3, r1) + REST_10GPRS(13, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr 990,r2 /* SRR2 */ + mtspr 991,r0 /* SRR3 */ + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfci + +/* Cache functions. +*/ +invalidate_icache: + mfspr r0,L1CSR1 + ori r0,r0,0x0002 + mtspr L1CSR1,r0 + isync + blr /* entire I cache */ + +invalidate_dcache: + mfspr r0,L1CSR0 + ori r0,r0,0x0002 + msync + isync + mtspr L1CSR0,r0 + isync + blr + + .globl icache_enable +icache_enable: + mflr r8 + bl invalidate_icache + mtlr r8 + isync + mfspr r4,L1CSR1 + ori r4,r4,0x0001 + oris r4,r4,0x0001 + mtspr L1CSR1,r4 + isync + blr + + .globl icache_disable +icache_disable: + mfspr r0,L1CSR1 + lis r1,0xfffffffe@h + ori r1,r1,0xfffffffe@l + and r0,r0,r1 + mtspr L1CSR1,r0 + isync + blr + + .globl icache_status +icache_status: + mfspr r3,L1CSR1 + srwi r3, r3, 31 /* >>31 => select bit 0 */ + blr + + .globl dcache_enable +dcache_enable: + mflr r8 + bl invalidate_dcache + mtlr r8 + isync + mfspr r0,L1CSR0 + ori r0,r0,0x0001 + oris r0,r0,0x0001 + msync + isync + mtspr L1CSR0,r0 + isync + blr + + .globl dcache_disable +dcache_disable: + mfspr r0,L1CSR0 + lis r1,0xfffffffe@h + ori r1,r1,0xfffffffe@l + and r0,r0,r1 + msync + isync + mtspr L1CSR0,r0 + isync + blr + + .globl dcache_status +dcache_status: + mfspr r3,L1CSR0 + srwi r3, r3, 31 /* >>31 => select bit 0 */ + blr + + .globl get_pir +get_pir: + mfspr r3, PIR + blr + + .globl get_pvr +get_pvr: + mfspr r3, PVR + blr + + .globl wr_tcr +wr_tcr: + mtspr TCR, r3 + blr + +/*------------------------------------------------------------------------------- */ +/* Function: in8 */ +/* Description: Input 8 bits */ +/*------------------------------------------------------------------------------- */ + .globl in8 +in8: + lbz r3,0x0000(r3) + blr + +/*------------------------------------------------------------------------------- */ +/* Function: out8 */ +/* Description: Output 8 bits */ +/*------------------------------------------------------------------------------- */ + .globl out8 +out8: + stb r4,0x0000(r3) + blr + +/*------------------------------------------------------------------------------- */ +/* Function: out16 */ +/* Description: Output 16 bits */ +/*------------------------------------------------------------------------------- */ + .globl out16 +out16: + sth r4,0x0000(r3) + blr + +/*------------------------------------------------------------------------------- */ +/* Function: out16r */ +/* Description: Byte reverse and output 16 bits */ +/*------------------------------------------------------------------------------- */ + .globl out16r +out16r: + sthbrx r4,r0,r3 + blr + +/*------------------------------------------------------------------------------- */ +/* Function: out32 */ +/* Description: Output 32 bits */ +/*------------------------------------------------------------------------------- */ + .globl out32 +out32: + stw r4,0x0000(r3) + blr + +/*------------------------------------------------------------------------------- */ +/* Function: out32r */ +/* Description: Byte reverse and output 32 bits */ +/*------------------------------------------------------------------------------- */ + .globl out32r +out32r: + stwbrx r4,r0,r3 + blr + +/*------------------------------------------------------------------------------- */ +/* Function: in16 */ +/* Description: Input 16 bits */ +/*------------------------------------------------------------------------------- */ + .globl in16 +in16: + lhz r3,0x0000(r3) + blr + +/*------------------------------------------------------------------------------- */ +/* Function: in16r */ +/* Description: Input 16 bits and byte reverse */ +/*------------------------------------------------------------------------------- */ + .globl in16r +in16r: + lhbrx r3,r0,r3 + blr + +/*------------------------------------------------------------------------------- */ +/* Function: in32 */ +/* Description: Input 32 bits */ +/*------------------------------------------------------------------------------- */ + .globl in32 +in32: + lwz 3,0x0000(3) + blr + +/*------------------------------------------------------------------------------- */ +/* Function: in32r */ +/* Description: Input 32 bits and byte reverse */ +/*------------------------------------------------------------------------------- */ + .globl in32r +in32r: + lwbrx r3,r0,r3 + blr + +/*------------------------------------------------------------------------------- */ +/* Function: ppcDcbf */ +/* Description: Data Cache block flush */ +/* Input: r3 = effective address */ +/* Output: none. */ +/*------------------------------------------------------------------------------- */ + .globl ppcDcbf +ppcDcbf: + dcbf r0,r3 + blr + +/*------------------------------------------------------------------------------- */ +/* Function: ppcDcbi */ +/* Description: Data Cache block Invalidate */ +/* Input: r3 = effective address */ +/* Output: none. */ +/*------------------------------------------------------------------------------- */ + .globl ppcDcbi +ppcDcbi: + dcbi r0,r3 + blr + +/*------------------------------------------------------------------------------- */ +/* Function: ppcSync */ +/* Description: Processor Synchronize */ +/* Input: none. */ +/* Output: none. */ +/*------------------------------------------------------------------------------- */ + .globl ppcSync +ppcSync: + sync + blr + +/*------------------------------------------------------------------------------*/ + +/* + * void relocate_code (addr_sp, gd, addr_moni) + * + * This "function" does not return, instead it continues in RAM + * after relocating the monitor code. + * + * r3 = dest + * r4 = src + * r5 = length in bytes + * r6 = cachelinesize + */ + .globl relocate_code +relocate_code: + mr r1, r3 /* Set new stack pointer */ + mr r9, r4 /* Save copy of Init Data pointer */ + mr r10, r5 /* Save copy of Destination Address */ + + mr r3, r5 /* Destination Address */ + lis r4, CFG_MONITOR_BASE@h /* Source Address */ + ori r4, r4, CFG_MONITOR_BASE@l + lwz r5,GOT(__init_end) + sub r5,r5,r4 + li r6, CFG_CACHELINE_SIZE /* Cache Line Size */ + + /* + * Fix GOT pointer: + * + * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address + * + * Offset: + */ + sub r15, r10, r4 + + /* First our own GOT */ + add r14, r14, r15 + /* the the one used by the C code */ + add r30, r30, r15 + + /* + * Now relocate code + */ + + cmplw cr1,r3,r4 + addi r0,r5,3 + srwi. r0,r0,2 + beq cr1,4f /* In place copy is not necessary */ + beq 7f /* Protect against 0 count */ + mtctr r0 + bge cr1,2f + + la r8,-4(r4) + la r7,-4(r3) +1: lwzu r0,4(r8) + stwu r0,4(r7) + bdnz 1b + b 4f + +2: slwi r0,r0,2 + add r8,r4,r0 + add r7,r3,r0 +3: lwzu r0,-4(r8) + stwu r0,-4(r7) + bdnz 3b + +/* + * Now flush the cache: note that we must start from a cache aligned + * address. Otherwise we might miss one cache line. + */ +4: cmpwi r6,0 + add r5,r3,r5 + beq 7f /* Always flush prefetch queue in any case */ + subi r0,r6,1 + andc r3,r3,r0 + mr r4,r3 +5: dcbst 0,r4 + add r4,r4,r6 + cmplw r4,r5 + blt 5b + sync /* Wait for all dcbst to complete on bus */ + mr r4,r3 +6: icbi 0,r4 + add r4,r4,r6 + cmplw r4,r5 + blt 6b +7: sync /* Wait for all icbi to complete on bus */ + isync + +/* + * 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 /* NEVER RETURNS! */ + +in_ram: + + /* + * Relocation Function, r14 point to got2+0x8000 + * + * Adjust got2 pointers, no need to check for 0, this code + * already puts a few entries in the table. + */ + li r0,__got2_entries@sectoff@l + la r3,GOT(_GOT2_TABLE_) + lwz r11,GOT(_GOT2_TABLE_) + mtctr r0 + sub r11,r3,r11 + addi r3,r3,-4 +1: lwzu r0,4(r3) + add r0,r0,r11 + stw r0,0(r3) + bdnz 1b + + /* + * Now adjust the fixups and the pointers to the fixups + * in case we need to move ourselves again. + */ +2: li r0,__fixup_entries@sectoff@l + lwz r3,GOT(_FIXUP_TABLE_) + cmpwi r0,0 + mtctr r0 + addi r3,r3,-4 + beq 4f +3: lwzu r4,4(r3) + lwzux r0,r4,r11 + add r0,r0,r11 + stw r10,0(r3) + stw r0,0(r4) + bdnz 3b +4: +clear_bss: + /* + * Now clear BSS segment + */ + lwz r3,GOT(__bss_start) + lwz r4,GOT(_end) + + cmplw 0, r3, r4 + beq 6f + + li r0, 0 +5: + stw r0, 0(r3) + addi r3, r3, 4 + cmplw 0, r3, r4 + bne 5b +6: + + mr r3, r9 /* Init 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: + lwz r7, GOT(_start) + lwz r8, GOT(_end_of_vectors) + + li r9, 0x100 /* reset vector always at 0x100 */ + + cmplw 0, r7, r8 + bgelr /* return if r7>=r8 - just in case */ + + mflr r4 /* save link register */ +1: + lwz r0, 0(r7) + stw r0, 0(r9) + addi r7, r7, 4 + addi r9, r9, 4 + cmplw 0, r7, r8 + bne 1b + + /* + * relocate `hdlr' and `int_return' entries + */ + li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET + li r8, Alignment - _start + EXC_OFF_SYS_RESET +2: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 2b + + li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET + bl trap_reloc + + li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET + bl trap_reloc + + li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET + li r8, SystemCall - _start + EXC_OFF_SYS_RESET +3: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 3b + + li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET + li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET +4: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 4b + + mtlr r4 /* restore link register */ + blr + + /* + * Function: relocate entries for one exception vector + */ +trap_reloc: + lwz r0, 0(r7) /* hdlr ... */ + add r0, r0, r3 /* ... += dest_addr */ + stw r0, 0(r7) + + lwz r0, 4(r7) /* int_return ... */ + add r0, r0, r3 /* ... += dest_addr */ + stw r0, 4(r7) + + blr + +#ifdef CFG_INIT_RAM_LOCK +.globl unlock_ram_in_cache +unlock_ram_in_cache: + /* invalidate the INIT_RAM section */ + lis r3, (CFG_INIT_RAM_ADDR & ~31)@h + ori r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l + li r2,512 + mtctr r2 +1: icbi r0, r3 + dcbi r0, r3 + addi r3, r3, 32 + bdnz 1b + sync /* Wait for all icbi to complete on bus */ + isync + blr +#endif diff --git a/cpu/mpc85xx/traps.c b/cpu/mpc85xx/traps.c new file mode 100644 index 0000000000..fd0b436cfa --- /dev/null +++ b/cpu/mpc85xx/traps.c @@ -0,0 +1,272 @@ +/* + * linux/arch/ppc/kernel/traps.c + * + * Copyright (C) 2003 Motorola + * Modified by Xianghua Xiao(x.xiao@motorola.com) + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@cs.anu.edu.au) + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include <common.h> +#include <command.h> +#include <asm/processor.h> + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +int (*debugger_exception_handler)(struct pt_regs *) = 0; +#endif + +/* Returns 0 if exception not found and fixup otherwise. */ +extern unsigned long search_exception_table(unsigned long); + +/* THIS NEEDS CHANGING to use the board info structure. + */ +#define END_OF_MEM (CFG_SDRAM_SIZE * 1024 * 1024) + + +static __inline__ void set_tsr(unsigned long val) +{ + asm volatile("mtspr 0x150, %0" : : "r" (val)); +} + +static __inline__ unsigned long get_esr(void) +{ + unsigned long val; + asm volatile("mfspr %0, 0x03e" : "=r" (val) :); + return val; +} + +#define ESR_MCI 0x80000000 +#define ESR_PIL 0x08000000 +#define ESR_PPR 0x04000000 +#define ESR_PTR 0x02000000 +#define ESR_DST 0x00800000 +#define ESR_DIZ 0x00400000 +#define ESR_U0F 0x00008000 + +#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +extern void do_bedbug_breakpoint(struct pt_regs *); +#endif + +/* + * Trap & Exception support + */ + +void +print_backtrace(unsigned long *sp) +{ + int cnt = 0; + unsigned long i; + + printf("Call backtrace: "); + while (sp) { + if ((uint)sp > END_OF_MEM) + break; + + i = sp[1]; + if (cnt++ % 7 == 0) + printf("\n"); + printf("%08lX ", i); + if (cnt > 32) break; + sp = (unsigned long *)*sp; + } + printf("\n"); +} + +void show_regs(struct pt_regs * regs) +{ + int i; + + printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n", + regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar); + printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n", + regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, + regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, + regs->msr&MSR_IR ? 1 : 0, + regs->msr&MSR_DR ? 1 : 0); + + printf("\n"); + for (i = 0; i < 32; i++) { + if ((i % 8) == 0) + { + printf("GPR%02d: ", i); + } + + printf("%08lX ", regs->gpr[i]); + if ((i % 8) == 7) + { + printf("\n"); + } + } +} + + +void +_exception(int signr, struct pt_regs *regs) +{ + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Exception in kernel pc %lx signal %d",regs->nip,signr); +} + +void +CritcalInputException(struct pt_regs *regs) +{ + panic("Critical Input Exception"); +} + +void +MachineCheckException(struct pt_regs *regs) +{ + unsigned long fixup; + + /* Probing PCI using config cycles cause this exception + * when a device is not present. Catch it and return to + * the PCI exception handler. + */ + if ((fixup = search_exception_table(regs->nip)) != 0) { + regs->nip = fixup; + return; + } + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + printf("Machine check in kernel mode.\n"); + printf("Caused by (from msr): "); + printf("regs %p ",regs); + switch( regs->msr & 0x0000F000) + { + case (1<<12) : + printf("Machine check signal - probably due to mm fault\n" + "with mmu off\n"); + break; + case (1<<13) : + printf("Transfer error ack signal\n"); + break; + case (1<<14) : + printf("Data parity signal\n"); + break; + case (1<<15) : + printf("Address parity signal\n"); + break; + default: + printf("Unknown values in msr\n"); + } + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("machine check"); +} + +void +AlignmentException(struct pt_regs *regs) +{ +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Alignment Exception"); +} + +void +ProgramCheckException(struct pt_regs *regs) +{ + long esr_val; + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + show_regs(regs); + + esr_val = get_esr(); + if( esr_val & ESR_PIL ) + printf( "** Illegal Instruction **\n" ); + else if( esr_val & ESR_PPR ) + printf( "** Privileged Instruction **\n" ); + else if( esr_val & ESR_PTR ) + printf( "** Trap Instruction **\n" ); + + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Program Check Exception"); +} + +void +PITException(struct pt_regs *regs) +{ + /* + * Reset PIT interrupt + */ + set_tsr(0x0c000000); + + /* + * Call timer_interrupt routine in interrupts.c + */ + timer_interrupt(NULL); +} + + +void +UnknownException(struct pt_regs *regs) +{ +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", + regs->nip, regs->msr, regs->trap); + _exception(0, regs); +} + +void +DebugException(struct pt_regs *regs) +{ + printf("Debugger trap at @ %lx\n", regs->nip ); + show_regs(regs); +#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) + do_bedbug_breakpoint( regs ); +#endif +} + +/* Probe an address by reading. If not present, return -1, otherwise + * return 0. + */ +int +addr_probe(uint *addr) +{ + return 0; +} diff --git a/cpu/mpc85xx/tsec.c b/cpu/mpc85xx/tsec.c new file mode 100644 index 0000000000..4a5731e6ae --- /dev/null +++ b/cpu/mpc85xx/tsec.c @@ -0,0 +1,441 @@ +/* + * tsec.c + * Motorola Three Speed Ethernet Controller driver + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * (C) Copyright 2003, Motorola, Inc. + * maintained by Xianghua Xiao (x.xiao@motorola.com) + * author Andy Fleming + * + */ + +#include <config.h> +#include <mpc85xx.h> +#include <common.h> +#include <malloc.h> +#include <net.h> +#include <command.h> + +#if defined(CONFIG_TSEC_ENET) +#include "tsec.h" + +#define TX_BUF_CNT 2 + +#undef TSEC_DEBUG +#ifdef TSEC_DEBUG +#define DBGPRINT(x) printf(x) +#else +#define DBGPRINT(x) +#endif + +static uint rxIdx; /* index of the current RX buffer */ +static uint txIdx; /* index of the current TX buffer */ + +typedef volatile struct rtxbd { + txbd8_t txbd[TX_BUF_CNT]; + rxbd8_t rxbd[PKTBUFSRX]; +} RTXBD; + +#ifdef __GNUC__ +static RTXBD rtx __attribute__ ((aligned(8))); +#else +#error "rtx must be 64-bit aligned" +#endif + +static int tsec_send(struct eth_device* dev, volatile void *packet, int length); +static int tsec_recv(struct eth_device* dev); +static int tsec_init(struct eth_device* dev, bd_t * bd); +static void tsec_halt(struct eth_device* dev); +static void init_registers(tsec_t *regs); +static void startup_tsec(tsec_t *regs); +static void init_phy(tsec_t *regs); + +/* Initialize device structure. returns 0 on failure, 1 on + * success */ +int tsec_initialize(bd_t *bis) +{ + struct eth_device* dev; + int i; + + dev = (struct eth_device*) malloc(sizeof *dev); + + if(dev == NULL) + return 0; + + memset(dev, 0, sizeof *dev); + + sprintf(dev->name, "MOTOROLA ETHERNET"); + dev->iobase = 0; + dev->priv = 0; + dev->init = tsec_init; + dev->halt = tsec_halt; + dev->send = tsec_send; + dev->recv = tsec_recv; + + /* Tell u-boot to get the addr from the env */ + for(i=0;i<6;i++) + dev->enetaddr[i] = 0; + + eth_register(dev); + + return 1; +} + + +/* Initializes data structures and registers for the controller, + * and brings the interface up */ +int tsec_init(struct eth_device* dev, bd_t * bd) +{ + tsec_t *regs; + uint tempval; + char tmpbuf[MAC_ADDR_LEN]; + int i; + + regs = (tsec_t *)(TSEC_BASE_ADDR); + + /* Make sure the controller is stopped */ + tsec_halt(dev); + + /* Reset the MAC */ + regs->maccfg1 |= MACCFG1_SOFT_RESET; + + /* Clear MACCFG1[Soft_Reset] */ + regs->maccfg1 &= ~(MACCFG1_SOFT_RESET); + + /* Init MACCFG2. Defaults to GMII/MII */ + regs->maccfg2 = MACCFG2_INIT_SETTINGS; + + /* Init ECNTRL */ + regs->ecntrl = ECNTRL_INIT_SETTINGS; + + /* Copy the station address into the address registers. + * Backwards, because little endian MACS are dumb */ + for(i=0;i<MAC_ADDR_LEN;i++) { + tmpbuf[MAC_ADDR_LEN - 1 - i] = bd->bi_enetaddr[i]; + } + (uint)(regs->macstnaddr1) = *((uint *)(tmpbuf)); + + tempval = *((uint *)(tmpbuf +4)); + + (uint)(regs->macstnaddr2) = tempval; + + /* Initialize the PHY */ + init_phy(regs); + + /* reset the indices to zero */ + rxIdx = 0; + txIdx = 0; + + /* Clear out (for the most part) the other registers */ + init_registers(regs); + + /* Ready the device for tx/rx */ + startup_tsec(regs); + + return 1; + +} + + +/* Reads from the register at offset in the PHY at phyid, */ +/* using the register set defined in regbase. It waits until the */ +/* bits in the miimstat are valid (miimind notvalid bit cleared), */ +/* and then passes those bits on to the variable specified in */ +/* value */ +/* Before it does the read, it needs to clear the command field */ +uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset) +{ + uint value; + + /* Put the address of the phy, and the register number into + * MIIMADD + */ + regbase->miimadd = (phyid << 8) | offset; + + /* Clear the command register, and wait */ + regbase->miimcom = 0; + asm("msync"); + + /* Initiate a read command, and wait */ + regbase->miimcom = MIIM_READ_COMMAND; + asm("msync"); + + /* Wait for the the indication that the read is done */ + while((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))); + + /* Grab the value read from the PHY */ + value = regbase->miimstat; + + return value; +} + +/* Setup the PHY */ +static void init_phy(tsec_t *regs) +{ + uint testval; + unsigned int timeout = TSEC_TIMEOUT; + + /* Assign a Physical address to the TBI */ + regs->tbipa=TBIPA_VALUE; + + /* reset the management interface */ + regs->miimcfg=MIIMCFG_RESET; + + regs->miimcfg=MIIMCFG_INIT_VALUE; + + /* Wait until the bus is free */ + while(regs->miimind & MIIMIND_BUSY); + +#ifdef CONFIG_PHY_CIS8201 + /* override PHY config settings */ + write_phy_reg(regs, 0, MIIM_AUX_CONSTAT, MIIM_AUXCONSTAT_INIT); + + /* Set up interface mode */ + write_phy_reg(regs, 0, MIIM_EXT_CON1, MIIM_EXTCON1_INIT); +#endif + + /* Set the PHY to gigabit, full duplex, Auto-negotiate */ + write_phy_reg(regs, 0, MIIM_CONTROL, MIIM_CONTROL_INIT); + + /* Wait until TBI_STATUS indicates AN is done */ + DBGPRINT("Waiting for Auto-negotiation to complete\n"); + testval=read_phy_reg(regs, 0, MIIM_TBI_STATUS); + + while((!(testval & MIIM_TBI_STATUS_AN_DONE))&& timeout--) { + testval=read_phy_reg(regs, 0, MIIM_TBI_STATUS); + } + + if(testval & MIIM_TBI_STATUS_AN_DONE) + DBGPRINT("Auto-negotiation done\n"); + else + DBGPRINT("Auto-negotiation timed-out.\n"); + +#ifdef CONFIG_PHY_CIS8201 + /* Find out what duplexity (duplicity?) we have */ + /* Read it twice to make sure */ + testval=read_phy_reg(regs, 0, MIIM_AUX_CONSTAT); + + if(testval & MIIM_AUXCONSTAT_DUPLEX) { + DBGPRINT("Enet starting in full duplex\n"); + regs->maccfg2 |= MACCFG2_FULL_DUPLEX; + } else { + DBGPRINT("Enet starting in half duplex\n"); + regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX; + } + + /* Also, we look to see what speed we are at + * if Gigabit, MACCFG2 goes in GMII, otherwise, + * MII mode. + */ + if((testval & MIIM_AUXCONSTAT_SPEED) != MIIM_AUXCONSTAT_GBIT) { + if((testval & MIIM_AUXCONSTAT_SPEED) == MIIM_AUXCONSTAT_100) + DBGPRINT("Enet starting in 100BT\n"); + else + DBGPRINT("Enet starting in 10BT\n"); + + /* mark the mode in MACCFG2 */ + regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII); + } else { + DBGPRINT("Enet starting in 1000BT\n"); + } + +#endif + +#ifdef CONFIG_PHY_M88E1011 + /* Read the PHY to see what speed and duplex we are */ + testval=read_phy_reg(regs, 0, MIIM_PHY_STATUS); + + timeout = TSEC_TIMEOUT; + while((!(testval & MIIM_PHYSTAT_SPDDONE)) && timeout--) { + testval = read_phy_reg(regs,0,MIIM_PHY_STATUS); + } + + if(!(testval & MIIM_PHYSTAT_SPDDONE)) + DBGPRINT("Enet: Speed not resolved\n"); + + testval=read_phy_reg(regs, 0, MIIM_PHY_STATUS); + if(testval & MIIM_PHYSTAT_DUPLEX) { + DBGPRINT("Enet starting in Full Duplex\n"); + regs->maccfg2 |= MACCFG2_FULL_DUPLEX; + } else { + DBGPRINT("Enet starting in Half Duplex\n"); + regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX; + } + + if(!((testval&MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_GBIT)) { + if((testval & MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_100) + DBGPRINT("Enet starting in 100BT\n"); + else + DBGPRINT("Enet starting in 10BT\n"); + + regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII); + } else { + DBGPRINT("Enet starting in 1000BT\n"); + } +#endif + +} + + +static void init_registers(tsec_t *regs) +{ + /* Clear IEVENT */ + regs->ievent = IEVENT_INIT_CLEAR; + + regs->imask = IMASK_INIT_CLEAR; + + regs->hash.iaddr0 = 0; + regs->hash.iaddr1 = 0; + regs->hash.iaddr2 = 0; + regs->hash.iaddr3 = 0; + regs->hash.iaddr4 = 0; + regs->hash.iaddr5 = 0; + regs->hash.iaddr6 = 0; + regs->hash.iaddr7 = 0; + + regs->hash.gaddr0 = 0; + regs->hash.gaddr1 = 0; + regs->hash.gaddr2 = 0; + regs->hash.gaddr3 = 0; + regs->hash.gaddr4 = 0; + regs->hash.gaddr5 = 0; + regs->hash.gaddr6 = 0; + regs->hash.gaddr7 = 0; + + regs->rctrl = 0x00000000; + + /* Init RMON mib registers */ + memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t)); + + regs->rmon.cam1 = 0xffffffff; + regs->rmon.cam2 = 0xffffffff; + + regs->mrblr = MRBLR_INIT_SETTINGS; + + regs->minflr = MINFLR_INIT_SETTINGS; + + regs->attr = ATTR_INIT_SETTINGS; + regs->attreli = ATTRELI_INIT_SETTINGS; + +} + +static void startup_tsec(tsec_t *regs) +{ + int i; + + /* Point to the buffer descriptors */ + regs->tbase = (unsigned int)(&rtx.txbd[txIdx]); + regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]); + + /* Initialize the Rx Buffer descriptors */ + for (i = 0; i < PKTBUFSRX; i++) { + rtx.rxbd[i].status = RXBD_EMPTY; + rtx.rxbd[i].length = 0; + rtx.rxbd[i].bufPtr = (uint)NetRxPackets[i]; + } + rtx.rxbd[PKTBUFSRX -1].status |= RXBD_WRAP; + + /* Initialize the TX Buffer Descriptors */ + for(i=0; i<TX_BUF_CNT; i++) { + rtx.txbd[i].status = 0; + rtx.txbd[i].length = 0; + rtx.txbd[i].bufPtr = 0; + } + rtx.txbd[TX_BUF_CNT -1].status |= TXBD_WRAP; + + /* Enable Transmit and Receive */ + regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN); + + /* Tell the DMA it is clear to go */ + regs->dmactrl |= DMACTRL_INIT_SETTINGS; + regs->tstat = TSTAT_CLEAR_THALT; + regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS); +} + +/* This returns the status bits of the device. The return value + * is never checked, and this is what the 8260 driver did, so we + * do the same. Presumably, this would be zero if there were no + * errors */ +static int tsec_send(struct eth_device* dev, volatile void *packet, int length) +{ + int i; + int result = 0; + tsec_t * regs = (tsec_t *)(TSEC_BASE_ADDR); + + /* Find an empty buffer descriptor */ + for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) { + if (i >= TOUT_LOOP) { + DBGPRINT("tsec: tx buffers full\n"); + return result; + } + } + + rtx.txbd[txIdx].bufPtr = (uint)packet; + rtx.txbd[txIdx].length = length; + rtx.txbd[txIdx].status |= (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT); + + /* Tell the DMA to go */ + regs->tstat = TSTAT_CLEAR_THALT; + + /* Wait for buffer to be transmitted */ + for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) { + if (i >= TOUT_LOOP) { + DBGPRINT("tsec: tx error\n"); + return result; + } + } + + txIdx = (txIdx + 1) % TX_BUF_CNT; + result = rtx.txbd[txIdx].status & TXBD_STATS; + + return result; +} + +static int tsec_recv(struct eth_device* dev) +{ + int length; + tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR); + + while(!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { + + length = rtx.rxbd[rxIdx].length; + + /* Send the packet up if there were no errors */ + if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) { + NetReceive(NetRxPackets[rxIdx], length - 4); + } + + rtx.rxbd[rxIdx].length = 0; + + /* Set the wrap bit if this is the last element in the list */ + rtx.rxbd[rxIdx].status = RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); + + rxIdx = (rxIdx + 1) % PKTBUFSRX; + } + + if(regs->ievent&IEVENT_BSY) { + regs->ievent = IEVENT_BSY; + regs->rstat = RSTAT_CLEAR_RHALT; + } + + return -1; + +} + + +static void tsec_halt(struct eth_device* dev) +{ + tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR); + + regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS); + regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS); + + while(!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC))); + + regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN); + +} +#endif /* CONFIG_TSEC_ENET */ diff --git a/cpu/mpc85xx/tsec.h b/cpu/mpc85xx/tsec.h new file mode 100644 index 0000000000..cfcfd393b5 --- /dev/null +++ b/cpu/mpc85xx/tsec.h @@ -0,0 +1,393 @@ +/* + * tsec.h + * + * Driver for the Motorola Triple Speed Ethernet Controller + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * (C) Copyright 2003, Motorola, Inc. + * maintained by Xianghua Xiao (x.xiao@motorola.com) + * author Andy Fleming + * + */ + +#ifndef __TSEC_H +#define __TSEC_H + +#include <net.h> +#include <mpc85xx.h> + +#define TSEC_BASE_ADDR (CFG_IMMR + 0x24000) +#define TSEC_MEM_SIZE 0x01000 + +#define MAC_ADDR_LEN 6 + +#define TSEC_TIMEOUT 1000000 +#define TOUT_LOOP 1000000 + +/* MAC register bits */ +#define MACCFG1_SOFT_RESET 0x80000000 +#define MACCFG1_RESET_RX_MC 0x00080000 +#define MACCFG1_RESET_TX_MC 0x00040000 +#define MACCFG1_RESET_RX_FUN 0x00020000 +#define MACCFG1_RESET_TX_FUN 0x00010000 +#define MACCFG1_LOOPBACK 0x00000100 +#define MACCFG1_RX_FLOW 0x00000020 +#define MACCFG1_TX_FLOW 0x00000010 +#define MACCFG1_SYNCD_RX_EN 0x00000008 +#define MACCFG1_RX_EN 0x00000004 +#define MACCFG1_SYNCD_TX_EN 0x00000002 +#define MACCFG1_TX_EN 0x00000001 + +#define MACCFG2_INIT_SETTINGS 0x00007205 +#define MACCFG2_FULL_DUPLEX 0x00000001 +#define MACCFG2_IF 0x00000300 +#define MACCFG2_MII 0x00000100 + +#define ECNTRL_INIT_SETTINGS 0x00001000 +#define ECNTRL_TBI_MODE 0x00000020 + +#define TBIPA_VALUE 0x1f +#define MIIMCFG_INIT_VALUE 0x00000003 +#define MIIMCFG_RESET 0x80000000 + +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_NOTVALID 0x00000004 + +#define MIIM_TBICON 0x11 +#define MIIM_TBICON_GMII 0x00000010 +#define MIIM_TBICON_AN 0x00000100 + +#define MIIM_CONTROL 0x00 +#define MIIM_CONTROL_INIT 0x00001140 +#define MIIM_ANEN 0x00001000 + +#define MIIM_TBI_STATUS 0x1 +#define MIIM_TBI_STATUS_AN_DONE 0x00000020 + +#define MIIM_TBI_ANEX 0x6 +#define MIIM_TBI_ANEX_NP 0x00000004 +#define MIIM_TBI_ANEX_PRX 0x00000002 + +#define MIIM_TBI_ANLPBPA 0x5 +#define MIIM_TBI_ANLPBPA_HALF 0x00000040 +#define MIIM_TBI_ANLPBPA_FULL 0x00000020 + +#ifdef CONFIG_PHY_CIS8201 +#define MIIM_AUX_CONSTAT 0x1c +#define MIIM_AUXCONSTAT_INIT 0x0004 +#define MIIM_AUXCONSTAT_DUPLEX 0x0020 +#define MIIM_AUXCONSTAT_SPEED 0x0018 +#define MIIM_AUXCONSTAT_GBIT 0x0010 +#define MIIM_AUXCONSTAT_100 0x0008 + +#define MIIM_EXT_CON1 0x17 +#define MIIM_EXTCON1_INIT 0x0000 + +#endif + +#ifdef CONFIG_PHY_M88E1011 +#define MIIM_ANAR 0x04 +#define MIIM_ANAR_ADVERTISEMENT 0x01e1 + +#define MIIM_GBIT_CON 0x09 +#define MIIM_GBIT_CON_ADVERT 0x1e00 + +#define MIIM_PHY_STATUS 0x11 +#define MIIM_PHYSTAT_SPEED 0xc000 +#define MIIM_PHYSTAT_GBIT 0x8000 +#define MIIM_PHYSTAT_100 0x4000 +#define MIIM_PHYSTAT_DUPLEX 0x2000 +#define MIIM_PHYSTAT_SPDDONE 0x0800 +#define MIIM_PHYSTAT_LINK 0x0400 +#endif + +#define MIIM_READ_COMMAND 0x00000001 + +#define MRBLR_INIT_SETTINGS PKTSIZE_ALIGN + +#define MINFLR_INIT_SETTINGS 0x00000040 + +#define DMACTRL_INIT_SETTINGS 0x000000c3 +#define DMACTRL_GRS 0x00000010 +#define DMACTRL_GTS 0x00000008 + +#define TSTAT_CLEAR_THALT 0x80000000 +#define RSTAT_CLEAR_RHALT 0x00800000 + +/* Write value to the PHY at phyid to the register at offset, */ +/* using the register space defined in regbase. Note that */ +/* miimcfg needs to have the clock speed setup correctly. This */ +/* macro will wait until the write is done before it finishes */ +#define write_phy_reg(regbase, phyid, offset, value) do { \ + int timeout=1000000; \ + regbase->miimadd = (phyid << 8) | offset; \ + regbase->miimcon = value; \ + asm("msync"); \ + while((regbase->miimind & MIIMIND_BUSY) && timeout--); \ +} while(0) + + +#define IEVENT_INIT_CLEAR 0xffffffff +#define IEVENT_BABR 0x80000000 +#define IEVENT_RXC 0x40000000 +#define IEVENT_BSY 0x20000000 +#define IEVENT_EBERR 0x10000000 +#define IEVENT_MSRO 0x04000000 +#define IEVENT_GTSC 0x02000000 +#define IEVENT_BABT 0x01000000 +#define IEVENT_TXC 0x00800000 +#define IEVENT_TXE 0x00400000 +#define IEVENT_TXB 0x00200000 +#define IEVENT_TXF 0x00100000 +#define IEVENT_IE 0x00080000 +#define IEVENT_LC 0x00040000 +#define IEVENT_CRL 0x00020000 +#define IEVENT_XFUN 0x00010000 +#define IEVENT_RXB0 0x00008000 +#define IEVENT_GRSC 0x00000100 +#define IEVENT_RXF0 0x00000080 + +#define IMASK_INIT_CLEAR 0x00000000 +#define IMASK_TXEEN 0x00400000 +#define IMASK_TXBEN 0x00200000 +#define IMASK_TXFEN 0x00100000 +#define IMASK_RXFEN0 0x00000080 + + +/* Default Attribute fields */ +#define ATTR_INIT_SETTINGS 0x000000c0 +#define ATTRELI_INIT_SETTINGS 0x00000000 + + +/* TxBD status field bits */ +#define TXBD_READY 0x8000 +#define TXBD_PADCRC 0x4000 +#define TXBD_WRAP 0x2000 +#define TXBD_INTERRUPT 0x1000 +#define TXBD_LAST 0x0800 +#define TXBD_CRC 0x0400 +#define TXBD_DEF 0x0200 +#define TXBD_HUGEFRAME 0x0080 +#define TXBD_LATECOLLISION 0x0080 +#define TXBD_RETRYLIMIT 0x0040 +#define TXBD_RETRYCOUNTMASK 0x003c +#define TXBD_UNDERRUN 0x0002 +#define TXBD_STATS 0x03ff + +/* RxBD status field bits */ +#define RXBD_EMPTY 0x8000 +#define RXBD_RO1 0x4000 +#define RXBD_WRAP 0x2000 +#define RXBD_INTERRUPT 0x1000 +#define RXBD_LAST 0x0800 +#define RXBD_FIRST 0x0400 +#define RXBD_MISS 0x0100 +#define RXBD_BROADCAST 0x0080 +#define RXBD_MULTICAST 0x0040 +#define RXBD_LARGE 0x0020 +#define RXBD_NONOCTET 0x0010 +#define RXBD_SHORT 0x0008 +#define RXBD_CRCERR 0x0004 +#define RXBD_OVERRUN 0x0002 +#define RXBD_TRUNCATED 0x0001 +#define RXBD_STATS 0x003f + +typedef struct txbd8 +{ + ushort status; /* Status Fields */ + ushort length; /* Buffer length */ + uint bufPtr; /* Buffer Pointer */ +} txbd8_t; + +typedef struct rxbd8 +{ + ushort status; /* Status Fields */ + ushort length; /* Buffer Length */ + uint bufPtr; /* Buffer Pointer */ +} rxbd8_t; + +typedef struct rmon_mib +{ + /* Transmit and Receive Counters */ + uint tr64; /* Transmit and Receive 64-byte Frame Counter */ + uint tr127; /* Transmit and Receive 65-127 byte Frame Counter */ + uint tr255; /* Transmit and Receive 128-255 byte Frame Counter */ + uint tr511; /* Transmit and Receive 256-511 byte Frame Counter */ + uint tr1k; /* Transmit and Receive 512-1023 byte Frame Counter */ + uint trmax; /* Transmit and Receive 1024-1518 byte Frame Counter */ + uint trmgv; /* Transmit and Receive 1519-1522 byte Good VLAN Frame */ + /* Receive Counters */ + uint rbyt; /* Receive Byte Counter */ + uint rpkt; /* Receive Packet Counter */ + uint rfcs; /* Receive FCS Error Counter */ + uint rmca; /* Receive Multicast Packet (Counter) */ + uint rbca; /* Receive Broadcast Packet */ + uint rxcf; /* Receive Control Frame Packet */ + uint rxpf; /* Receive Pause Frame Packet */ + uint rxuo; /* Receive Unknown OP Code */ + uint raln; /* Receive Alignment Error */ + uint rflr; /* Receive Frame Length Error */ + uint rcde; /* Receive Code Error */ + uint rcse; /* Receive Carrier Sense Error */ + uint rund; /* Receive Undersize Packet */ + uint rovr; /* Receive Oversize Packet */ + uint rfrg; /* Receive Fragments */ + uint rjbr; /* Receive Jabber */ + uint rdrp; /* Receive Drop */ + /* Transmit Counters */ + uint tbyt; /* Transmit Byte Counter */ + uint tpkt; /* Transmit Packet */ + uint tmca; /* Transmit Multicast Packet */ + uint tbca; /* Transmit Broadcast Packet */ + uint txpf; /* Transmit Pause Control Frame */ + uint tdfr; /* Transmit Deferral Packet */ + uint tedf; /* Transmit Excessive Deferral Packet */ + uint tscl; /* Transmit Single Collision Packet */ + /* (0x2_n700) */ + uint tmcl; /* Transmit Multiple Collision Packet */ + uint tlcl; /* Transmit Late Collision Packet */ + uint txcl; /* Transmit Excessive Collision Packet */ + uint tncl; /* Transmit Total Collision */ + + uint res2; + + uint tdrp; /* Transmit Drop Frame */ + uint tjbr; /* Transmit Jabber Frame */ + uint tfcs; /* Transmit FCS Error */ + uint txcf; /* Transmit Control Frame */ + uint tovr; /* Transmit Oversize Frame */ + uint tund; /* Transmit Undersize Frame */ + uint tfrg; /* Transmit Fragments Frame */ + /* General Registers */ + uint car1; /* Carry Register One */ + uint car2; /* Carry Register Two */ + uint cam1; /* Carry Register One Mask */ + uint cam2; /* Carry Register Two Mask */ +} rmon_mib_t; + +typedef struct tsec_hash_regs +{ + uint iaddr0; /* Individual Address Register 0 */ + uint iaddr1; /* Individual Address Register 1 */ + uint iaddr2; /* Individual Address Register 2 */ + uint iaddr3; /* Individual Address Register 3 */ + uint iaddr4; /* Individual Address Register 4 */ + uint iaddr5; /* Individual Address Register 5 */ + uint iaddr6; /* Individual Address Register 6 */ + uint iaddr7; /* Individual Address Register 7 */ + uint res1[24]; + uint gaddr0; /* Group Address Register 0 */ + uint gaddr1; /* Group Address Register 1 */ + uint gaddr2; /* Group Address Register 2 */ + uint gaddr3; /* Group Address Register 3 */ + uint gaddr4; /* Group Address Register 4 */ + uint gaddr5; /* Group Address Register 5 */ + uint gaddr6; /* Group Address Register 6 */ + uint gaddr7; /* Group Address Register 7 */ + uint res2[24]; +} tsec_hash_t; + +typedef struct tsec +{ + /* General Control and Status Registers (0x2_n000) */ + uint res000[4]; + + uint ievent; /* Interrupt Event */ + uint imask; /* Interrupt Mask */ + uint edis; /* Error Disabled */ + uint res01c; + uint ecntrl; /* Ethernet Control */ + uint minflr; /* Minimum Frame Length */ + uint ptv; /* Pause Time Value */ + uint dmactrl; /* DMA Control */ + uint tbipa; /* TBI PHY Address */ + + uint res034[3]; + uint res040[48]; + + /* Transmit Control and Status Registers (0x2_n100) */ + uint tctrl; /* Transmit Control */ + uint tstat; /* Transmit Status */ + uint res108; + uint tbdlen; /* Tx BD Data Length */ + uint res110[5]; + uint ctbptr; /* Current TxBD Pointer */ + uint res128[23]; + uint tbptr; /* TxBD Pointer */ + uint res188[30]; + /* (0x2_n200) */ + uint res200; + uint tbase; /* TxBD Base Address */ + uint res208[42]; + uint ostbd; /* Out of Sequence TxBD */ + uint ostbdp; /* Out of Sequence Tx Data Buffer Pointer */ + uint res2b8[18]; + + /* Receive Control and Status Registers (0x2_n300) */ + uint rctrl; /* Receive Control */ + uint rstat; /* Receive Status */ + uint res308; + uint rbdlen; /* RxBD Data Length */ + uint res310[4]; + uint res320; + uint crbptr; /* Current Receive Buffer Pointer */ + uint res328[6]; + uint mrblr; /* Maximum Receive Buffer Length */ + uint res344[16]; + uint rbptr; /* RxBD Pointer */ + uint res388[30]; + /* (0x2_n400) */ + uint res400; + uint rbase; /* RxBD Base Address */ + uint res408[62]; + + /* MAC Registers (0x2_n500) */ + uint maccfg1; /* MAC Configuration #1 */ + uint maccfg2; /* MAC Configuration #2 */ + uint ipgifg; /* Inter Packet Gap/Inter Frame Gap */ + uint hafdup; /* Half-duplex */ + uint maxfrm; /* Maximum Frame */ + uint res514; + uint res518; + + uint res51c; + + uint miimcfg; /* MII Management: Configuration */ + uint miimcom; /* MII Management: Command */ + uint miimadd; /* MII Management: Address */ + uint miimcon; /* MII Management: Control */ + uint miimstat; /* MII Management: Status */ + uint miimind; /* MII Management: Indicators */ + + uint res538; + + uint ifstat; /* Interface Status */ + uint macstnaddr1; /* Station Address, part 1 */ + uint macstnaddr2; /* Station Address, part 2 */ + uint res548[46]; + + /* (0x2_n600) */ + uint res600[32]; + + /* RMON MIB Registers (0x2_n680-0x2_n73c) */ + rmon_mib_t rmon; + uint res740[48]; + + /* Hash Function Registers (0x2_n800) */ + tsec_hash_t hash; + + uint res900[128]; + + /* Pattern Registers (0x2_nb00) */ + uint resb00[62]; + uint attr; /* Default Attribute Register */ + uint attreli; /* Default Attribute Extract Length and Index */ + + /* TSEC Future Expansion Space (0x2_nc00-0x2_nffc) */ + uint resc00[256]; +} tsec_t; + +#endif /* __TSEC_H */ |