diff options
author | Stefan Roese <sr@denx.de> | 2007-03-31 13:44:12 +0200 |
---|---|---|
committer | Stefan Roese <sr@denx.de> | 2007-03-31 13:44:12 +0200 |
commit | 0e7d4916afaf83083b9b70ad779f29f7b57bd8ed (patch) | |
tree | 40e9396ee819149a89f520f551d1ed31cb8f5216 /cpu/bf537 | |
parent | da6ebc1bc082cbe3b6bbde079cafe09f7ebbad4b (diff) | |
parent | 6db7d0af2336c126e4d4b2f248cc23516bdd46a8 (diff) | |
download | u-boot-imx-0e7d4916afaf83083b9b70ad779f29f7b57bd8ed.zip u-boot-imx-0e7d4916afaf83083b9b70ad779f29f7b57bd8ed.tar.gz u-boot-imx-0e7d4916afaf83083b9b70ad779f29f7b57bd8ed.tar.bz2 |
Merge with git://www.denx.de/git/u-boot.git
Diffstat (limited to 'cpu/bf537')
-rw-r--r-- | cpu/bf537/Makefile | 52 | ||||
-rw-r--r-- | cpu/bf537/cache.S | 128 | ||||
-rw-r--r-- | cpu/bf537/config.mk | 27 | ||||
-rw-r--r-- | cpu/bf537/cpu.c | 227 | ||||
-rw-r--r-- | cpu/bf537/cpu.h | 66 | ||||
-rw-r--r-- | cpu/bf537/flush.S | 403 | ||||
-rw-r--r-- | cpu/bf537/i2c.c | 460 | ||||
-rw-r--r-- | cpu/bf537/init_sdram.S | 174 | ||||
-rw-r--r-- | cpu/bf537/init_sdram_bootrom_initblock.S | 199 | ||||
-rw-r--r-- | cpu/bf537/interrupt.S | 246 | ||||
-rw-r--r-- | cpu/bf537/interrupts.c | 174 | ||||
-rw-r--r-- | cpu/bf537/ints.c | 117 | ||||
-rw-r--r-- | cpu/bf537/serial.c | 194 | ||||
-rw-r--r-- | cpu/bf537/serial.h | 77 | ||||
-rw-r--r-- | cpu/bf537/start.S | 579 | ||||
-rw-r--r-- | cpu/bf537/start1.S | 38 | ||||
-rw-r--r-- | cpu/bf537/traps.c | 241 | ||||
-rw-r--r-- | cpu/bf537/video.c | 194 | ||||
-rw-r--r-- | cpu/bf537/video.h | 25 |
19 files changed, 3621 insertions, 0 deletions
diff --git a/cpu/bf537/Makefile b/cpu/bf537/Makefile new file mode 100644 index 0000000..61c7338 --- /dev/null +++ b/cpu/bf537/Makefile @@ -0,0 +1,52 @@ +# U-boot - Makefile +# +# Copyright (c) 2005 blackfin.uclinux.org +# +# (C) Copyright 2000-2004 +# 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 $(TOPDIR)/config.mk + +LIB = $(obj)lib$(CPU).a + +START = start.o start1.o interrupt.o cache.o flush.o init_sdram.o +COBJS = cpu.o traps.o ints.o serial.o interrupts.o video.o i2c.o + +EXTRA = init_sdram_bootrom_initblock.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) $(obj).depend $(EXTRA) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/bf537/cache.S b/cpu/bf537/cache.S new file mode 100644 index 0000000..5bda5bf --- /dev/null +++ b/cpu/bf537/cache.S @@ -0,0 +1,128 @@ +#define ASSEMBLY +#include <asm/linkage.h> +#include <config.h> +#include <asm/blackfin.h> + +.text +.align 2 +ENTRY(_blackfin_icache_flush_range) + R2 = -32; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; + 1: + IFLUSH[P0++]; + CC = P0 < P1(iu); + IF CC JUMP 1b(bp); + IFLUSH[P0]; + SSYNC; + RTS; + +ENTRY(_blackfin_dcache_flush_range) + R2 = -32; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; +1: + FLUSH[P0++]; + CC = P0 < P1(iu); + IF CC JUMP 1b(bp); + FLUSH[P0]; + SSYNC; + RTS; + +ENTRY(_icache_invalidate) +ENTRY(_invalidate_entire_icache) + [--SP] = (R7:5); + + P0.L = (IMEM_CONTROL & 0xFFFF); + P0.H = (IMEM_CONTROL >> 16); + R7 =[P0]; + + /* + * Clear the IMC bit , All valid bits in the instruction + * cache are set to the invalid state + */ + BITCLR(R7, IMC_P); + CLI R6; + /* SSYNC required before invalidating cache. */ + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + /* Configures the instruction cache agian */ + R6 = (IMC | ENICPLB); + R7 = R7 | R6; + + CLI R6; + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + (R7:5) =[SP++]; + RTS; + +/* + * Invalidate the Entire Data cache by + * clearing DMC[1:0] bits + */ +ENTRY(_invalidate_entire_dcache) +ENTRY(_dcache_invalidate) + [--SP] = (R7:6); + + P0.L = (DMEM_CONTROL & 0xFFFF); + P0.H = (DMEM_CONTROL >> 16); + R7 =[P0]; + + /* + * Clear the DMC[1:0] bits, All valid bits in the data + * cache are set to the invalid state + */ + BITCLR(R7, DMC0_P); + BITCLR(R7, DMC1_P); + CLI R6; + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + /* Configures the data cache again */ + + R6 = (ACACHE_BCACHE | ENDCPLB | PORT_PREF0); + R7 = R7 | R6; + + CLI R6; + SSYNC; + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + (R7:6) =[SP++]; + RTS; + +ENTRY(_blackfin_dcache_invalidate_range) + R2 = -32; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; +1: + FLUSHINV[P0++]; + CC = P0 < P1(iu); + IF CC JUMP 1b(bp); + + /* + * If the data crosses a cache line, then we'll be pointing to + * the last cache line, but won't have flushed/invalidated it yet, so do + * one more. + */ + FLUSHINV[P0]; + SSYNC; + RTS; diff --git a/cpu/bf537/config.mk b/cpu/bf537/config.mk new file mode 100644 index 0000000..4d57d9c --- /dev/null +++ b/cpu/bf537/config.mk @@ -0,0 +1,27 @@ +# U-boot - config.mk +# +# Copyright (c) 2005 blackfin.uclinux.org +# +# (C) Copyright 2000-2004 +# 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 +# + +PLATFORM_RELFLAGS += -mcpu=bf537 -ffixed-P5 diff --git a/cpu/bf537/cpu.c b/cpu/bf537/cpu.c new file mode 100644 index 0000000..cb8dc3c --- /dev/null +++ b/cpu/bf537/cpu.c @@ -0,0 +1,227 @@ +/* + * U-boot - cpu.c CPU specific functions + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/blackfin.h> +#include <command.h> +#include <asm/entry.h> +#include <asm/cplb.h> +#include <asm/io.h> + +#define CACHE_ON 1 +#define CACHE_OFF 0 + +extern unsigned int icplb_table[page_descriptor_table_size][2]; +extern unsigned int dcplb_table[page_descriptor_table_size][2]; + +int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + __asm__ __volatile__("cli r3;" "P0 = %0;" "JUMP (P0);"::"r"(L1_ISRAM) + ); + + return 0; +} + +/* These functions are just used to satisfy the linker */ +int cpu_init(void) +{ + return 0; +} + +int cleanup_before_linux(void) +{ + return 0; +} + +void icache_enable(void) +{ + unsigned int *I0, *I1; + int i, j = 0; + + if ((*pCHIPID >> 28) < 2) + return; + + /* Before enable icache, disable it first */ + icache_disable(); + I0 = (unsigned int *)ICPLB_ADDR0; + I1 = (unsigned int *)ICPLB_DATA0; + + /* make sure the locked ones go in first */ + for (i = 0; i < page_descriptor_table_size; i++) { + if (CPLB_LOCK & icplb_table[i][1]) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + icplb_table[i][0], icplb_table[i][1]); + *I0++ = icplb_table[i][0]; + *I1++ = icplb_table[i][1]; + j++; + } + } + + for (i = 0; i < page_descriptor_table_size; i++) { + if (!(CPLB_LOCK & icplb_table[i][1])) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + icplb_table[i][0], icplb_table[i][1]); + *I0++ = icplb_table[i][0]; + *I1++ = icplb_table[i][1]; + j++; + if (j == 16) { + break; + } + } + } + + /* Fill the rest with invalid entry */ + if (j <= 15) { + for (; j < 16; j++) { + debug("filling %i with 0", j); + *I1++ = 0x0; + } + + } + + cli(); + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL = IMC | ENICPLB; + sync(); + sti(); +} + +void icache_disable(void) +{ + if ((*pCHIPID >> 28) < 2) + return; + cli(); + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL &= ~(IMC | ENICPLB); + sync(); + sti(); +} + +int icache_status(void) +{ + unsigned int value; + value = *(unsigned int *)IMEM_CONTROL; + + if (value & (IMC | ENICPLB)) + return CACHE_ON; + else + return CACHE_OFF; +} + +void dcache_enable(void) +{ + unsigned int *I0, *I1; + unsigned int temp; + int i, j = 0; + + /* Before enable dcache, disable it first */ + dcache_disable(); + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + + /* make sure the locked ones go in first */ + for (i = 0; i < page_descriptor_table_size; i++) { + if (CPLB_LOCK & dcplb_table[i][1]) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + *I0++ = dcplb_table[i][0]; + *I1++ = dcplb_table[i][1]; + j++; + } else { + debug("skip %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + } + } + + for (i = 0; i < page_descriptor_table_size; i++) { + if (!(CPLB_LOCK & dcplb_table[i][1])) { + debug("adding %02i %02i 0x%08x 0x%08x\n", i, j, + dcplb_table[i][0], dcplb_table[i][1]); + *I0++ = dcplb_table[i][0]; + *I1++ = dcplb_table[i][1]; + j++; + if (j == 16) { + break; + } + } + } + + /* Fill the rest with invalid entry */ + if (j <= 15) { + for (; j < 16; j++) { + debug("filling %i with 0", j); + *I1++ = 0x0; + } + } + + cli(); + temp = *(unsigned int *)DMEM_CONTROL; + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL = + ACACHE_BCACHE | ENDCPLB | PORT_PREF0 | temp; + sync(); + sti(); +} + +void dcache_disable(void) +{ + unsigned int *I0, *I1; + int i; + + cli(); + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL &= + ~(ACACHE_BCACHE | ENDCPLB | PORT_PREF0); + sync(); + sti(); + + /* after disable dcache, + * clear it so we don't confuse the next application + */ + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + + for (i = 0; i < 16; i++) { + *I0++ = 0x0; + *I1++ = 0x0; + } +} + +int dcache_status(void) +{ + unsigned int value; + value = *(unsigned int *)DMEM_CONTROL; + + if (value & (ENDCPLB)) + return CACHE_ON; + else + return CACHE_OFF; +} diff --git a/cpu/bf537/cpu.h b/cpu/bf537/cpu.h new file mode 100644 index 0000000..821363e --- /dev/null +++ b/cpu/bf537/cpu.h @@ -0,0 +1,66 @@ +/* + * U-boot - cpu.h + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _CPU_H_ +#define _CPU_H_ + +#include <command.h> + +#define INTERNAL_IRQS (32) +#define NUM_IRQ_NODES 16 +#define DEF_INTERRUPT_FLAGS 1 +#define MAX_TIM_LOAD 0xFFFFFFFF + +void blackfin_irq_panic(int reason, struct pt_regs *reg); +extern void dump(struct pt_regs *regs); +void display_excp(void); +asmlinkage void evt_nmi(void); +asmlinkage void evt_exception(void); +asmlinkage void trap(void); +asmlinkage void evt_ivhw(void); +asmlinkage void evt_rst(void); +asmlinkage void evt_timer(void); +asmlinkage void evt_evt7(void); +asmlinkage void evt_evt8(void); +asmlinkage void evt_evt9(void); +asmlinkage void evt_evt10(void); +asmlinkage void evt_evt11(void); +asmlinkage void evt_evt12(void); +asmlinkage void evt_evt13(void); +asmlinkage void evt_soft_int1(void); +asmlinkage void evt_system_call(void); +void blackfin_irq_panic(int reason, struct pt_regs *regs); +void blackfin_free_irq(unsigned int irq, void *dev_id); +void call_isr(int irq, struct pt_regs *fp); +void blackfin_do_irq(int vec, struct pt_regs *fp); +void blackfin_init_IRQ(void); +void blackfin_enable_irq(unsigned int irq); +void blackfin_disable_irq(unsigned int irq); +extern int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]); +int blackfin_request_irq(unsigned int irq, + void (*handler) (int, void *, struct pt_regs *), + unsigned long flags, const char *devname, + void *dev_id); +void timer_init(void); +#endif diff --git a/cpu/bf537/flush.S b/cpu/bf537/flush.S new file mode 100644 index 0000000..c260a8f --- /dev/null +++ b/cpu/bf537/flush.S @@ -0,0 +1,403 @@ +/* Copyright (C) 2003 Analog Devices, Inc. All Rights Reserved. + * Copyright (C) 2004 LG SOft India. All Rights Reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. + */ +#define ASSEMBLY + +#include <asm/linkage.h> +#include <asm/cplb.h> +#include <config.h> +#include <asm/blackfin.h> + +.text + +/* This is an external function being called by the user + * application through __flush_cache_all. Currently this function + * serves the purpose of flushing all the pending writes in + * in the instruction cache. + */ + +ENTRY(_flush_instruction_cache) + [--SP] = ( R7:6, P5:4 ); + LINK 12; + SP += -12; + P5.H = (ICPLB_ADDR0 >> 16); + P5.L = (ICPLB_ADDR0 & 0xFFFF); + P4.H = (ICPLB_DATA0 >> 16); + P4.L = (ICPLB_DATA0 & 0xFFFF); + R7 = CPLB_VALID | CPLB_L1_CHBL; + R6 = 16; +inext: R0 = [P5++]; + R1 = [P4++]; + [--SP] = RETS; + CALL _icplb_flush; /* R0 = page, R1 = data*/ + RETS = [SP++]; +iskip: R6 += -1; + CC = R6; + IF CC JUMP inext; + SSYNC; + SP += 12; + UNLINK; + ( R7:6, P5:4 ) = [SP++]; + RTS; + +/* This is an internal function to flush all pending + * writes in the cache associated with a particular ICPLB. + * + * R0 - page's start address + * R1 - CPLB's data field. + */ + +.align 2 +ENTRY(_icplb_flush) + [--SP] = ( R7:0, P5:0 ); + [--SP] = LC0; + [--SP] = LT0; + [--SP] = LB0; + [--SP] = LC1; + [--SP] = LT1; + [--SP] = LB1; + + /* If it's a 1K or 4K page, then it's quickest to + * just systematically flush all the addresses in + * the page, regardless of whether they're in the + * cache, or dirty. If it's a 1M or 4M page, there + * are too many addresses, and we have to search the + * cache for lines corresponding to the page. + */ + + CC = BITTST(R1, 17); /* 1MB or 4MB */ + IF !CC JUMP iflush_whole_page; + + /* We're only interested in the page's size, so extract + * this from the CPLB (bits 17:16), and scale to give an + * offset into the page_size and page_prefix tables. + */ + + R1 <<= 14; + R1 >>= 30; + R1 <<= 2; + + /* We can also determine the sub-bank used, because this is + * taken from bits 13:12 of the address. + */ + + R3 = ((12<<8)|2); /* Extraction pattern */ + nop; /* Anamoly 05000209 */ + R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits */ + + /* Save in extraction pattern for later deposit. */ + R3.H = R4.L << 0; + + /* So: + * R0 = Page start + * R1 = Page length (actually, offset into size/prefix tables) + * R3 = sub-bank deposit values + * + * The cache has 2 Ways, and 64 sets, so we iterate through + * the sets, accessing the tag for each Way, for our Bank and + * sub-bank, looking for dirty, valid tags that match our + * address prefix. + */ + + P5.L = (ITEST_COMMAND & 0xFFFF); + P5.H = (ITEST_COMMAND >> 16); + P4.L = (ITEST_DATA0 & 0xFFFF); + P4.H = (ITEST_DATA0 >> 16); + + P0.L = page_prefix_table; + P0.H = page_prefix_table; + P1 = R1; + R5 = 0; /* Set counter*/ + P0 = P1 + P0; + R4 = [P0]; /* This is the address prefix*/ + + /* We're reading (bit 1==0) the tag (bit 2==0), and we + * don't care about which double-word, since we're only + * fetching tags, so we only have to set Set, Bank, + * Sub-bank and Way. + */ + + P2 = 4; + LSETUP (ifs1, ife1) LC1 = P2; +ifs1: P0 = 32; /* iterate over all sets*/ + LSETUP (ifs0, ife0) LC0 = P0; +ifs0: R6 = R5 << 5; /* Combine set*/ + R6.H = R3.H << 0 ; /* and sub-bank*/ + [P5] = R6; /* Issue Command*/ + SSYNC; /* CSYNC will not work here :(*/ + R7 = [P4]; /* and read Tag.*/ + CC = BITTST(R7, 0); /* Check if valid*/ + IF !CC JUMP ifskip; /* and skip if not.*/ + + /* Compare against the page address. First, plant bits 13:12 + * into the tag, since those aren't part of the returned data. + */ + + R7 = DEPOSIT(R7, R3); /* set 13:12*/ + R1 = R7 & R4; /* Mask off lower bits*/ + CC = R1 == R0; /* Compare against page start.*/ + IF !CC JUMP ifskip; /* Skip it if it doesn't match.*/ + + /* Tag address matches against page, so this is an entry + * we must flush. + */ + + R7 >>= 10; /* Mask off the non-address bits*/ + R7 <<= 10; + P3 = R7; + IFLUSH [P3]; /* And flush the entry*/ +ifskip: +ife0: R5 += 1; /* Advance to next Set*/ +ife1: NOP; + +ifinished: + SSYNC; /* Ensure the data gets out to mem.*/ + + /*Finished. Restore context.*/ + LB1 = [SP++]; + LT1 = [SP++]; + LC1 = [SP++]; + LB0 = [SP++]; + LT0 = [SP++]; + LC0 = [SP++]; + ( R7:0, P5:0 ) = [SP++]; + RTS; + +iflush_whole_page: + /* It's a 1K or 4K page, so quicker to just flush the + * entire page. + */ + + P1 = 32; /* For 1K pages*/ + P2 = P1 << 2; /* For 4K pages*/ + P0 = R0; /* Start of page*/ + CC = BITTST(R1, 16); /* Whether 1K or 4K*/ + IF CC P1 = P2; + P1 += -1; /* Unroll one iteration*/ + SSYNC; + IFLUSH [P0++]; /* because CSYNC can't end loops.*/ + LSETUP (isall, ieall) LC0 = P1; +isall:IFLUSH [P0++]; +ieall: NOP; + SSYNC; + JUMP ifinished; + +/* This is an external function being called by the user + * application through __flush_cache_all. Currently this function + * serves the purpose of flushing all the pending writes in + * in the data cache. + */ + +ENTRY(_flush_data_cache) + [--SP] = ( R7:6, P5:4 ); + LINK 12; + SP += -12; + P5.H = (DCPLB_ADDR0 >> 16); + P5.L = (DCPLB_ADDR0 & 0xFFFF); + P4.H = (DCPLB_DATA0 >> 16); + P4.L = (DCPLB_DATA0 & 0xFFFF); + R7 = CPLB_VALID | CPLB_L1_CHBL | CPLB_DIRTY (Z); + R6 = 16; +next: R0 = [P5++]; + R1 = [P4++]; + CC = BITTST(R1, 14); /* Is it write-through?*/ + IF CC JUMP skip; /* If so, ignore it.*/ + R2 = R1 & R7; /* Is it a dirty, cached page?*/ + CC = R2; + IF !CC JUMP skip; /* If not, ignore it.*/ + [--SP] = RETS; + CALL _dcplb_flush; /* R0 = page, R1 = data*/ + RETS = [SP++]; +skip: R6 += -1; + CC = R6; + IF CC JUMP next; + SSYNC; + SP += 12; + UNLINK; + ( R7:6, P5:4 ) = [SP++]; + RTS; + +/* This is an internal function to flush all pending + * writes in the cache associated with a particular DCPLB. + * + * R0 - page's start address + * R1 - CPLB's data field. + */ + +.align 2 +ENTRY(_dcplb_flush) + [--SP] = ( R7:0, P5:0 ); + [--SP] = LC0; + [--SP] = LT0; + [--SP] = LB0; + [--SP] = LC1; + [--SP] = LT1; + [--SP] = LB1; + + /* If it's a 1K or 4K page, then it's quickest to + * just systematically flush all the addresses in + * the page, regardless of whether they're in the + * cache, or dirty. If it's a 1M or 4M page, there + * are too many addresses, and we have to search the + * cache for lines corresponding to the page. + */ + + CC = BITTST(R1, 17); /* 1MB or 4MB */ + IF !CC JUMP dflush_whole_page; + + /* We're only interested in the page's size, so extract + * this from the CPLB (bits 17:16), and scale to give an + * offset into the page_size and page_prefix tables. + */ + + R1 <<= 14; + R1 >>= 30; + R1 <<= 2; + + /* The page could be mapped into Bank A or Bank B, depending + * on (a) whether both banks are configured as cache, and + * (b) on whether address bit A[x] is set. x is determined + * by DCBS in DMEM_CONTROL + */ + + R2 = 0; /* Default to Bank A (Bank B would be 1)*/ + + P0.L = (DMEM_CONTROL & 0xFFFF); + P0.H = (DMEM_CONTROL >> 16); + + R3 = [P0]; /* If Bank B is not enabled as cache*/ + CC = BITTST(R3, 2); /* then Bank A is our only option.*/ + IF CC JUMP bank_chosen; + + R4 = 1<<14; /* If DCBS==0, use A[14].*/ + R5 = R4 << 7; /* If DCBS==1, use A[23];*/ + CC = BITTST(R3, 4); + IF CC R4 = R5; /* R4 now has either bit 14 or bit 23 set.*/ + R5 = R0 & R4; /* Use it to test the Page address*/ + CC = R5; /* and if that bit is set, we use Bank B,*/ + R2 = CC; /* else we use Bank A.*/ + R2 <<= 23; /* The Bank selection's at posn 23.*/ + +bank_chosen: + + /* We can also determine the sub-bank used, because this is + * taken from bits 13:12 of the address. + */ + + R3 = ((12<<8)|2); /* Extraction pattern */ + nop; /*Anamoly 05000209*/ + R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits*/ + /* Save in extraction pattern for later deposit.*/ + R3.H = R4.L << 0; + + /* So: + * R0 = Page start + * R1 = Page length (actually, offset into size/prefix tables) + * R2 = Bank select mask + * R3 = sub-bank deposit values + * + * The cache has 2 Ways, and 64 sets, so we iterate through + * the sets, accessing the tag for each Way, for our Bank and + * sub-bank, looking for dirty, valid tags that match our + * address prefix. + */ + + P5.L = (DTEST_COMMAND & 0xFFFF); + P5.H = (DTEST_COMMAND >> 16); + P4.L = (DTEST_DATA0 & 0xFFFF); + P4.H = (DTEST_DATA0 >> 16); + + P0.L = page_prefix_table; + P0.H = page_prefix_table; + P1 = R1; + R5 = 0; /* Set counter*/ + P0 = P1 + P0; + R4 = [P0]; /* This is the address prefix*/ + + + /* We're reading (bit 1==0) the tag (bit 2==0), and we + * don't care about which double-word, since we're only + * fetching tags, so we only have to set Set, Bank, + * Sub-bank and Way. + */ + + P2 = 2; + LSETUP (fs1, fe1) LC1 = P2; +fs1: P0 = 64; /* iterate over all sets*/ + LSETUP (fs0, fe0) LC0 = P0; +fs0: R6 = R5 << 5; /* Combine set*/ + R6.H = R3.H << 0 ; /* and sub-bank*/ + R6 = R6 | R2; /* and Bank. Leave Way==0 at first.*/ + BITSET(R6,14); + [P5] = R6; /* Issue Command*/ + SSYNC; + R7 = [P4]; /* and read Tag.*/ + CC = BITTST(R7, 0); /* Check if valid*/ + IF !CC JUMP fskip; /* and skip if not.*/ + CC = BITTST(R7, 1); /* Check if dirty*/ + IF !CC JUMP fskip; /* and skip if not.*/ + + /* Compare against the page address. First, plant bits 13:12 + * into the tag, since those aren't part of the returned data. + */ + + R7 = DEPOSIT(R7, R3); /* set 13:12*/ + R1 = R7 & R4; /* Mask off lower bits*/ + CC = R1 == R0; /* Compare against page start.*/ + IF !CC JUMP fskip; /* Skip it if it doesn't match.*/ + + /* Tag address matches against page, so this is an entry + * we must flush. + */ + + R7 >>= 10; /* Mask off the non-address bits*/ + R7 <<= 10; + P3 = R7; + SSYNC; + FLUSHINV [P3]; /* And flush the entry*/ +fskip: +fe0: R5 += 1; /* Advance to next Set*/ +fe1: BITSET(R2, 26); /* Go to next Way.*/ + +dfinished: + SSYNC; /* Ensure the data gets out to mem.*/ + + /*Finished. Restore context.*/ + LB1 = [SP++]; + LT1 = [SP++]; + LC1 = [SP++]; + LB0 = [SP++]; + LT0 = [SP++]; + LC0 = [SP++]; + ( R7:0, P5:0 ) = [SP++]; + RTS; + +dflush_whole_page: + + /* It's a 1K or 4K page, so quicker to just flush the + * entire page. + */ + + P1 = 32; /* For 1K pages*/ + P2 = P1 << 2; /* For 4K pages*/ + P0 = R0; /* Start of page*/ + CC = BITTST(R1, 16); /* Whether 1K or 4K*/ + IF CC P1 = P2; + P1 += -1; /* Unroll one iteration*/ + SSYNC; + FLUSHINV [P0++]; /* because CSYNC can't end loops.*/ + LSETUP (eall, eall) LC0 = P1; +eall: FLUSHINV [P0++]; + SSYNC; + JUMP dfinished; + +.align 4; +page_prefix_table: +.byte4 0xFFFFFC00; /* 1K */ +.byte4 0xFFFFF000; /* 4K */ +.byte4 0xFFF00000; /* 1M */ +.byte4 0xFFC00000; /* 4M */ +.page_prefix_table.end: diff --git a/cpu/bf537/i2c.c b/cpu/bf537/i2c.c new file mode 100644 index 0000000..3b0d026 --- /dev/null +++ b/cpu/bf537/i2c.c @@ -0,0 +1,460 @@ +/**************************************************************** + * $ID: i2c.c 24 Oct 2006 12:00:00 +0800 $ * + * * + * Description: * + * * + * Maintainer: sonicz <sonic.zhang@analog.com> * + * * + * CopyRight (c) 2006 Analog Device * + * All rights reserved. * + * * + * This file is free software; * + * you are free to modify and/or redistribute it * + * under the terms of the GNU General Public Licence (GPL).* + * * + ****************************************************************/ + +#include <common.h> + +#ifdef CONFIG_HARD_I2C + +#include <asm/blackfin.h> +#include <i2c.h> +#include <asm/io.h> + +#define bfin_read16(addr) ({ unsigned __v; \ + __asm__ __volatile__ (\ + "%0 = w[%1] (z);\n\t"\ + : "=d"(__v) : "a"(addr)); (unsigned short)__v; }) + +#define bfin_write16(addr,val) ({\ + __asm__ __volatile__ (\ + "w[%0] = %1;\n\t"\ + : : "a"(addr) , "d"(val) : "memory");}) + +/* Two-Wire Interface (0xFFC01400 - 0xFFC014FF) */ +#define bfin_read_TWI_CLKDIV() bfin_read16(TWI_CLKDIV) +#define bfin_write_TWI_CLKDIV(val) bfin_write16(TWI_CLKDIV,val) +#define bfin_read_TWI_CONTROL() bfin_read16(TWI_CONTROL) +#define bfin_write_TWI_CONTROL(val) bfin_write16(TWI_CONTROL,val) +#define bfin_read_TWI_SLAVE_CTL() bfin_read16(TWI_SLAVE_CTL) +#define bfin_write_TWI_SLAVE_CTL(val) bfin_write16(TWI_SLAVE_CTL,val) +#define bfin_read_TWI_SLAVE_STAT() bfin_read16(TWI_SLAVE_STAT) +#define bfin_write_TWI_SLAVE_STAT(val) bfin_write16(TWI_SLAVE_STAT,val) +#define bfin_read_TWI_SLAVE_ADDR() bfin_read16(TWI_SLAVE_ADDR) +#define bfin_write_TWI_SLAVE_ADDR(val) bfin_write16(TWI_SLAVE_ADDR,val) +#define bfin_read_TWI_MASTER_CTL() bfin_read16(TWI_MASTER_CTL) +#define bfin_write_TWI_MASTER_CTL(val) bfin_write16(TWI_MASTER_CTL,val) +#define bfin_read_TWI_MASTER_STAT() bfin_read16(TWI_MASTER_STAT) +#define bfin_write_TWI_MASTER_STAT(val) bfin_write16(TWI_MASTER_STAT,val) +#define bfin_read_TWI_MASTER_ADDR() bfin_read16(TWI_MASTER_ADDR) +#define bfin_write_TWI_MASTER_ADDR(val) bfin_write16(TWI_MASTER_ADDR,val) +#define bfin_read_TWI_INT_STAT() bfin_read16(TWI_INT_STAT) +#define bfin_write_TWI_INT_STAT(val) bfin_write16(TWI_INT_STAT,val) +#define bfin_read_TWI_INT_MASK() bfin_read16(TWI_INT_MASK) +#define bfin_write_TWI_INT_MASK(val) bfin_write16(TWI_INT_MASK,val) +#define bfin_read_TWI_FIFO_CTL() bfin_read16(TWI_FIFO_CTL) +#define bfin_write_TWI_FIFO_CTL(val) bfin_write16(TWI_FIFO_CTL,val) +#define bfin_read_TWI_FIFO_STAT() bfin_read16(TWI_FIFO_STAT) +#define bfin_write_TWI_FIFO_STAT(val) bfin_write16(TWI_FIFO_STAT,val) +#define bfin_read_TWI_XMT_DATA8() bfin_read16(TWI_XMT_DATA8) +#define bfin_write_TWI_XMT_DATA8(val) bfin_write16(TWI_XMT_DATA8,val) +#define bfin_read_TWI_XMT_DATA16() bfin_read16(TWI_XMT_DATA16) +#define bfin_write_TWI_XMT_DATA16(val) bfin_write16(TWI_XMT_DATA16,val) +#define bfin_read_TWI_RCV_DATA8() bfin_read16(TWI_RCV_DATA8) +#define bfin_write_TWI_RCV_DATA8(val) bfin_write16(TWI_RCV_DATA8,val) +#define bfin_read_TWI_RCV_DATA16() bfin_read16(TWI_RCV_DATA16) +#define bfin_write_TWI_RCV_DATA16(val) bfin_write16(TWI_RCV_DATA16,val) + +#ifdef DEBUG_I2C +#define PRINTD(fmt,args...) do { \ + DECLARE_GLOBAL_DATA_PTR; \ + if (gd->have_console) \ + printf(fmt ,##args); \ + } while (0) +#else +#define PRINTD(fmt,args...) +#endif + +#ifndef CONFIG_TWICLK_KHZ +#define CONFIG_TWICLK_KHZ 50 +#endif + +/* All transfers are described by this data structure */ +struct i2c_msg { + u16 addr; /* slave address */ + u16 flags; +#define I2C_M_STOP 0x2 +#define I2C_M_RD 0x1 + u16 len; /* msg length */ + u8 *buf; /* pointer to msg data */ +}; + +/** + * i2c_reset: - reset the host controller + * + */ + +static void i2c_reset(void) +{ + /* Disable TWI */ + bfin_write_TWI_CONTROL(0); + sync(); + + /* Set TWI internal clock as 10MHz */ + bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F); + + /* Set Twi interface clock as specified */ + if (CONFIG_TWICLK_KHZ > 400) + bfin_write_TWI_CLKDIV(((5 * 1024 / 400) << 8) | ((5 * 1024 / + 400) & 0xFF)); + else + bfin_write_TWI_CLKDIV(((5 * 1024 / + CONFIG_TWICLK_KHZ) << 8) | ((5 * 1024 / + CONFIG_TWICLK_KHZ) + & 0xFF)); + + /* Enable TWI */ + bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); + sync(); +} + +int wait_for_completion(struct i2c_msg *msg, int timeout_count) +{ + unsigned short twi_int_stat; + unsigned short mast_stat; + int i; + + for (i = 0; i < timeout_count; i++) { + twi_int_stat = bfin_read_TWI_INT_STAT(); + mast_stat = bfin_read_TWI_MASTER_STAT(); + + if (XMTSERV & twi_int_stat) { + /* Transmit next data */ + if (msg->len > 0) { + bfin_write_TWI_XMT_DATA8(*(msg->buf++)); + msg->len--; + } else if (msg->flags & I2C_M_STOP) + bfin_write_TWI_MASTER_CTL + (bfin_read_TWI_MASTER_CTL() | STOP); + sync(); + /* Clear status */ + bfin_write_TWI_INT_STAT(XMTSERV); + sync(); + i = 0; + } + if (RCVSERV & twi_int_stat) { + if (msg->len > 0) { + /* Receive next data */ + *(msg->buf++) = bfin_read_TWI_RCV_DATA8(); + msg->len--; + } else if (msg->flags & I2C_M_STOP) { + bfin_write_TWI_MASTER_CTL + (bfin_read_TWI_MASTER_CTL() | STOP); + sync(); + } + /* Clear interrupt source */ + bfin_write_TWI_INT_STAT(RCVSERV); + sync(); + i = 0; + } + if (MERR & twi_int_stat) { + bfin_write_TWI_INT_STAT(MERR); + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_STAT(0x3e); + bfin_write_TWI_MASTER_CTL(0); + sync(); + /* + * if both err and complete int stats are set, + * return proper results. + */ + if (MCOMP & twi_int_stat) { + bfin_write_TWI_INT_STAT(MCOMP); + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_CTL(0); + sync(); + /* + * If it is a quick transfer, + * only address bug no data, not an err. + */ + if (msg->len == 0 && mast_stat & BUFRDERR) + return 0; + /* + * If address not acknowledged return -3, + * else return 0. + */ + else if (!(mast_stat & ANAK)) + return 0; + else + return -3; + } + return -1; + } + if (MCOMP & twi_int_stat) { + bfin_write_TWI_INT_STAT(MCOMP); + sync(); + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_CTL(0); + sync(); + return 0; + } + } + if (msg->flags & I2C_M_RD) + return -4; + else + return -2; +} + +/** + * i2c_transfer: - Transfer one byte over the i2c bus + * + * This function can tranfer a byte over the i2c bus in both directions. + * It is used by the public API functions. + * + * @return: 0: transfer successful + * -1: transfer fail + * -2: transmit timeout + * -3: ACK missing + * -4: receive timeout + * -5: controller not ready + */ +int i2c_transfer(struct i2c_msg *msg) +{ + int ret = 0; + int timeout_count = 10000; + int len = msg->len; + + if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) { + ret = -5; + goto transfer_error; + } + + while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) ; + + /* Set Transmit device address */ + bfin_write_TWI_MASTER_ADDR(msg->addr); + + /* + * FIFO Initiation. + * Data in FIFO should be discarded before start a new operation. + */ + bfin_write_TWI_FIFO_CTL(0x3); + sync(); + bfin_write_TWI_FIFO_CTL(0); + sync(); + + if (!(msg->flags & I2C_M_RD)) { + /* Transmit first data */ + if (msg->len > 0) { + PRINTD("1 in i2c_transfer: buf=%d, len=%d\n", *msg->buf, + len); + bfin_write_TWI_XMT_DATA8(*(msg->buf++)); + msg->len--; + sync(); + } + } + + /* clear int stat */ + bfin_write_TWI_INT_STAT(MERR | MCOMP | XMTSERV | RCVSERV); + + /* Interrupt mask . Enable XMT, RCV interrupt */ + bfin_write_TWI_INT_MASK(MCOMP | MERR | + ((msg->flags & I2C_M_RD) ? RCVSERV : XMTSERV)); + sync(); + + if (len > 0 && len <= 255) + bfin_write_TWI_MASTER_CTL((len << 6)); + else if (msg->len > 255) { + bfin_write_TWI_MASTER_CTL((0xff << 6)); + msg->flags &= I2C_M_STOP; + } else + bfin_write_TWI_MASTER_CTL(0); + + /* Master enable */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | + ((msg->flags & I2C_M_RD) + ? MDIR : 0) | ((CONFIG_TWICLK_KHZ > + 100) ? FAST : 0)); + sync(); + + ret = wait_for_completion(msg, timeout_count); + PRINTD("3 in i2c_transfer: ret=%d\n", ret); + +transfer_error: + switch (ret) { + case 1: + PRINTD(("i2c_transfer: error: transfer fail\n")); + break; + case 2: + PRINTD(("i2c_transfer: error: transmit timeout\n")); + break; + case 3: + PRINTD(("i2c_transfer: error: ACK missing\n")); + break; + case 4: + PRINTD(("i2c_transfer: error: receive timeout\n")); + break; + case 5: + PRINTD(("i2c_transfer: error: controller not ready\n")); + i2c_reset(); + break; + default: + break; + } + return ret; + +} + +/* ---------------------------------------------------------------------*/ +/* API Functions */ +/* ---------------------------------------------------------------------*/ + +void i2c_init(int speed, int slaveaddr) +{ + i2c_reset(); +} + +/** + * i2c_probe: - Test if a chip answers for a given i2c address + * + * @chip: address of the chip which is searched for + * @return: 0 if a chip was found, -1 otherwhise + */ + +int i2c_probe(uchar chip) +{ + struct i2c_msg msg; + u8 probebuf; + + i2c_reset(); + + probebuf = 0; + msg.addr = chip; + msg.flags = 0; + msg.len = 1; + msg.buf = &probebuf; + if (i2c_transfer(&msg)) + return -1; + + msg.addr = chip; + msg.flags = I2C_M_RD; + msg.len = 1; + msg.buf = &probebuf; + if (i2c_transfer(&msg)) + return -1; + + return 0; +} + +/** + * i2c_read: - Read multiple bytes from an i2c device + * + * chip: I2C chip address, range 0..127 + * addr: Memory (register) address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one + * register) + * buffer: Where to read/write the data + * len: How many bytes to read/write + * + * Returns: 0 on success, not 0 on failure + */ + +int i2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len) +{ + struct i2c_msg msg; + u8 addr_bytes[3]; /* lowest...highest byte of data address */ + + PRINTD("i2c_read: chip=0x%x, addr=0x%x, alen=0x%x, len=0x%x\n", chip, + addr, alen, len); + + if (alen > 0) { + addr_bytes[0] = (u8) ((addr >> 0) & 0x000000FF); + addr_bytes[1] = (u8) ((addr >> 8) & 0x000000FF); + addr_bytes[2] = (u8) ((addr >> 16) & 0x000000FF); + msg.addr = chip; + msg.flags = 0; + msg.len = alen; + msg.buf = addr_bytes; + if (i2c_transfer(&msg)) + return -1; + } + + /* start read sequence */ + PRINTD(("i2c_read: start read sequence\n")); + msg.addr = chip; + msg.flags = I2C_M_RD; + msg.len = len; + msg.buf = buffer; + if (i2c_transfer(&msg)) + return -1; + + return 0; +} + +/** + * i2c_write: - Write multiple bytes to an i2c device + * + * chip: I2C chip address, range 0..127 + * addr: Memory (register) address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one + * register) + * buffer: Where to read/write the data + * len: How many bytes to read/write + * + * Returns: 0 on success, not 0 on failure + */ + +int i2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len) +{ + struct i2c_msg msg; + u8 addr_bytes[3]; /* lowest...highest byte of data address */ + + PRINTD + ("i2c_write: chip=0x%x, addr=0x%x, alen=0x%x, len=0x%x, buf0=0x%x\n", + chip, addr, alen, len, buffer[0]); + + /* chip address write */ + if (alen > 0) { + addr_bytes[0] = (u8) ((addr >> 0) & 0x000000FF); + addr_bytes[1] = (u8) ((addr >> 8) & 0x000000FF); + addr_bytes[2] = (u8) ((addr >> 16) & 0x000000FF); + msg.addr = chip; + msg.flags = 0; + msg.len = alen; + msg.buf = addr_bytes; + if (i2c_transfer(&msg)) + return -1; + } + + /* start read sequence */ + PRINTD(("i2c_write: start write sequence\n")); + msg.addr = chip; + msg.flags = 0; + msg.len = len; + msg.buf = buffer; + if (i2c_transfer(&msg)) + return -1; + + return 0; + +} + +uchar i2c_reg_read(uchar chip, uchar reg) +{ + uchar buf; + + PRINTD("i2c_reg_read: chip=0x%02x, reg=0x%02x\n", chip, reg); + i2c_read(chip, reg, 0, &buf, 1); + return (buf); +} + +void i2c_reg_write(uchar chip, uchar reg, uchar val) +{ + PRINTD("i2c_reg_write: chip=0x%02x, reg=0x%02x, val=0x%02x\n", chip, + reg, val); + i2c_write(chip, reg, 0, &val, 1); +} + +#endif /* CONFIG_HARD_I2C */ diff --git a/cpu/bf537/init_sdram.S b/cpu/bf537/init_sdram.S new file mode 100644 index 0000000..897a589 --- /dev/null +++ b/cpu/bf537/init_sdram.S @@ -0,0 +1,174 @@ +#define ASSEMBLY + +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> +#include <asm/mem_init.h> +.global init_sdram; + +#if (BFIN_BOOT_MODE != BF537_UART_BOOT) +#if (CONFIG_CCLK_DIV == 1) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 +#endif +#if (CONFIG_CCLK_DIV == 2) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 +#endif +#if (CONFIG_CCLK_DIV == 4) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 +#endif +#if (CONFIG_CCLK_DIV == 8) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 +#endif +#ifndef CONFIG_CCLK_ACT_DIV +#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly +#endif +#endif + +init_sdram: + [--SP] = ASTAT; + [--SP] = RETS; + [--SP] = (R7:0); + [--SP] = (P5:0); + +#if (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT) + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; + w[p0] = r0.l; + SSYNC; + + p0.h = hi(SPI_BAUD); + p0.l = lo(SPI_BAUD); + r0.l = CONFIG_SPI_BAUD; + w[p0] = r0.l; + SSYNC; +#endif + +#if (BFIN_BOOT_MODE != BF537_UART_BOOT) + +#ifdef CONFIG_BF537 + /* Enable PHY CLK buffer output */ + p0.h = hi(VR_CTL); + p0.l = lo(VR_CTL); + r0.l = w[p0]; + bitset(r0, 14); + w[p0] = r0.l; + ssync; +#endif + /* + * PLL_LOCKCNT - how many SCLK Cycles to delay while PLL becomes stable + */ + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + /* + * Put SDRAM in self-refresh, incase anything is running + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + /* + * Set PLL_CTL with the value that we calculate in R0 + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over */ + r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +check_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump check_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; +#endif + + /* + * Now, Initialize the SDRAM, + * start with the SDRAM Refresh Rate Control Register + */ + p0.l = lo(EBIU_SDRRC); + p0.h = hi(EBIU_SDRRC); + r0 = mem_SDRRC; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Memory Bank Control Register - bank specific parameters + */ + p0.l = (EBIU_SDBCTL & 0xFFFF); + p0.h = (EBIU_SDBCTL >> 16); + r0 = mem_SDBCTL; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Global Control Register - global programmable parameters + * Disable self-refresh + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITCLR (R0, 24); + + /* + * Check if SDRAM is already powered up, if it is, enable self-refresh + */ + p0.h = hi(EBIU_SDSTAT); + p0.l = lo(EBIU_SDSTAT); + r2.l = w[p0]; + cc = bittst(r2,3); + if !cc jump skip; + NOP; + BITSET (R0, 23); +skip: + [P2] = R0; + SSYNC; + + /* Write in the new value in the register */ + R0.L = lo(mem_SDGCTL); + R0.H = hi(mem_SDGCTL); + [P2] = R0; + SSYNC; + nop; + + (P5:0) = [SP++]; + (R7:0) = [SP++]; + RETS = [SP++]; + ASTAT = [SP++]; + RTS; diff --git a/cpu/bf537/init_sdram_bootrom_initblock.S b/cpu/bf537/init_sdram_bootrom_initblock.S new file mode 100644 index 0000000..f9adbb9 --- /dev/null +++ b/cpu/bf537/init_sdram_bootrom_initblock.S @@ -0,0 +1,199 @@ +#define ASSEMBLY + +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> +#include <asm/mem_init.h> +.global init_sdram; + +#if (BFIN_BOOT_MODE != BF537_UART_BOOT) +#if (CONFIG_CCLK_DIV == 1) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 +#endif +#if (CONFIG_CCLK_DIV == 2) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 +#endif +#if (CONFIG_CCLK_DIV == 4) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 +#endif +#if (CONFIG_CCLK_DIV == 8) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 +#endif +#ifndef CONFIG_CCLK_ACT_DIV +#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly +#endif +#endif + +init_sdram: + [--SP] = ASTAT; + [--SP] = RETS; + [--SP] = (R7:0); + [--SP] = (P5:0); + +#if (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT) + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; + w[p0] = r0.l; + SSYNC; + + p0.h = hi(SPI_BAUD); + p0.l = lo(SPI_BAUD); + r0.l = CONFIG_SPI_BAUD_INITBLOCK; + w[p0] = r0.l; + SSYNC; +#endif + +#if (BFIN_BOOT_MODE != BF537_UART_BOOT) + +#ifdef CONFIG_BF537 + /* Enable PHY CLK buffer output */ + p0.h = hi(VR_CTL); + p0.l = lo(VR_CTL); + r0.l = w[p0]; + bitset(r0, 14); + w[p0] = r0.l; + ssync; +#endif + /* + * PLL_LOCKCNT - how many SCLK Cycles to delay while PLL becomes stable + */ + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + /* + * Put SDRAM in self-refresh, incase anything is running + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + /* + * Set PLL_CTL with the value that we calculate in R0 + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over */ + r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +check_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump check_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; +#endif + + /* + * We now are running at speed, time to set the Async mem bank wait states + * This will speed up execution, since we are normally running from FLASH. + */ + + p2.h = (EBIU_AMBCTL1 >> 16); + p2.l = (EBIU_AMBCTL1 & 0xFFFF); + r0.h = (AMBCTL1VAL >> 16); + r0.l = (AMBCTL1VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMBCTL0 >> 16); + p2.l = (EBIU_AMBCTL0 & 0xFFFF); + r0.h = (AMBCTL0VAL >> 16); + r0.l = (AMBCTL0VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMGCTL >> 16); + p2.l = (EBIU_AMGCTL & 0xffff); + r0 = AMGCTLVAL; + w[p2] = r0; + ssync; + + /* + * Now, Initialize the SDRAM, + * start with the SDRAM Refresh Rate Control Register + */ + p0.l = lo(EBIU_SDRRC); + p0.h = hi(EBIU_SDRRC); + r0 = mem_SDRRC; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Memory Bank Control Register - bank specific parameters + */ + p0.l = (EBIU_SDBCTL & 0xFFFF); + p0.h = (EBIU_SDBCTL >> 16); + r0 = mem_SDBCTL; + w[p0] = r0.l; + ssync; + + /* + * SDRAM Global Control Register - global programmable parameters + * Disable self-refresh + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITCLR (R0, 24); + + /* + * Check if SDRAM is already powered up, if it is, enable self-refresh + */ + p0.h = hi(EBIU_SDSTAT); + p0.l = lo(EBIU_SDSTAT); + r2.l = w[p0]; + cc = bittst(r2,3); + if !cc jump skip; + NOP; + BITSET (R0, 23); +skip: + [P2] = R0; + SSYNC; + + /* Write in the new value in the register */ + R0.L = lo(mem_SDGCTL); + R0.H = hi(mem_SDGCTL); + [P2] = R0; + SSYNC; + nop; + + (P5:0) = [SP++]; + (R7:0) = [SP++]; + RETS = [SP++]; + ASTAT = [SP++]; + RTS; diff --git a/cpu/bf537/interrupt.S b/cpu/bf537/interrupt.S new file mode 100644 index 0000000..a8be34f --- /dev/null +++ b/cpu/bf537/interrupt.S @@ -0,0 +1,246 @@ +/* + * U-boot - interrupt.S Processing of interrupts and exception handling + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This file is based on interrupt.S + * + * Copyright (C) 2003 Metrowerks, Inc. <mwaddel@metrowerks.com> + * Copyright (C) 2002 Arcturus Networks Ltd. Ted Ma <mated@sympatico.ca> + * Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, + * Kenneth Albanowski <kjahds@kjahds.com>, + * The Silver Hammer Group, Ltd. + * + * (c) 1995, Dionne & Associates + * (c) 1995, DKG Display Tech. + * + * This file is also based on exception.asm + * (C) Copyright 2001-2005 - Analog Devices, Inc. All rights reserved. + * + * 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 + */ + +#define ASSEMBLY +#include <config.h> +#include <asm/blackfin.h> +#include <asm/hw_irq.h> +#include <asm/entry.h> +#include <asm/blackfin_defs.h> + +.global _blackfin_irq_panic; + +.text +.align 2 + +#ifndef CONFIG_KGDB +.global _evt_emulation +_evt_emulation: + SAVE_CONTEXT + r0 = IRQ_EMU; + r1 = seqstat; + sp += -12; + call _blackfin_irq_panic; + sp += 12; + rte; +#endif + +.global _evt_nmi +_evt_nmi: + SAVE_CONTEXT + r0 = IRQ_NMI; + r1 = RETN; + sp += -12; + call _blackfin_irq_panic; + sp += 12; + +_evt_nmi_exit: + rtn; + +.global _trap +_trap: + SAVE_ALL_SYS + r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ + sp += -12; + call _trap_c + sp += 12; + RESTORE_ALL_SYS + rtx; + +.global _evt_rst +_evt_rst: + SAVE_CONTEXT + r0 = IRQ_RST; + r1 = RETN; + sp += -12; + call _do_reset; + sp += 12; + +_evt_rst_exit: + rtn; + +irq_panic: + r0 = IRQ_EVX; + r1 = sp; + sp += -12; + call _blackfin_irq_panic; + sp += 12; + +.global _evt_ivhw +_evt_ivhw: + SAVE_CONTEXT + RAISE 14; + +_evt_ivhw_exit: + rti; + +.global _evt_timer +_evt_timer: + SAVE_CONTEXT + r0 = IRQ_CORETMR; + sp += -12; + /* Polling method used now. */ + /* call timer_int; */ + sp += 12; + RESTORE_CONTEXT + rti; + nop; + +.global _evt_evt7 +_evt_evt7: + SAVE_CONTEXT + r0 = 7; + sp += -12; + call _process_int; + sp += 12; + +evt_evt7_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt8 +_evt_evt8: + SAVE_CONTEXT + r0 = 8; + sp += -12; + call _process_int; + sp += 12; + +evt_evt8_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt9 +_evt_evt9: + SAVE_CONTEXT + r0 = 9; + sp += -12; + call _process_int; + sp += 12; + +evt_evt9_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt10 +_evt_evt10: + SAVE_CONTEXT + r0 = 10; + sp += -12; + call _process_int; + sp += 12; + +evt_evt10_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt11 +_evt_evt11: + SAVE_CONTEXT + r0 = 11; + sp += -12; + call _process_int; + sp += 12; + +evt_evt11_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt12 +_evt_evt12: + SAVE_CONTEXT + r0 = 12; + sp += -12; + call _process_int; + sp += 12; +evt_evt12_exit: + RESTORE_CONTEXT + rti; + +.global _evt_evt13 +_evt_evt13: + SAVE_CONTEXT + r0 = 13; + sp += -12; + call _process_int; + sp += 12; + +evt_evt13_exit: + RESTORE_CONTEXT + rti; + +.global _evt_system_call +_evt_system_call: + [--sp] = r0; + [--SP] = RETI; + r0 = [sp++]; + r0 += 2; + [--sp] = r0; + RETI = [SP++]; + r0 = [SP++]; + SAVE_CONTEXT + sp += -12; + call _exception_handle; + sp += 12; + RESTORE_CONTEXT + RTI; + +evt_system_call_exit: + rti; + +.global _evt_soft_int1 +_evt_soft_int1: + [--sp] = r0; + [--SP] = RETI; + r0 = [sp++]; + r0 += 2; + [--sp] = r0; + RETI = [SP++]; + r0 = [SP++]; + SAVE_CONTEXT + sp += -12; + call _exception_handle; + sp += 12; + RESTORE_CONTEXT + RTI; + +evt_soft_int1_exit: + rti; diff --git a/cpu/bf537/interrupts.c b/cpu/bf537/interrupts.c new file mode 100644 index 0000000..2ca76ec --- /dev/null +++ b/cpu/bf537/interrupts.c @@ -0,0 +1,174 @@ +/* + * U-boot - interrupts.c Interrupt related routines + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on interrupts.c + * Copyright 1996 Roman Zippel + * Copyright 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca> + * Copyright 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca> + * Copyright 2003 Metrowerks/Motorola + * Copyright 2003 Bas Vermeulen <bas@buyways.nl>, + * BuyWays B.V. (www.buyways.nl) + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/machdep.h> +#include <asm/irq.h> +#include <config.h> +#include <asm/blackfin.h> +#include "cpu.h" + +static ulong timestamp; +static ulong last_time; +static int int_flag; + +int irq_flags; /* needed by asm-blackfin/system.h */ + +/* Functions just to satisfy the linker */ + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On BF533 it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On BF533 it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + ulong tbclk; + + tbclk = CFG_HZ; + return tbclk; +} + +void enable_interrupts(void) +{ + restore_flags(int_flag); +} + +int disable_interrupts(void) +{ + save_and_cli(int_flag); + return 1; +} + +int interrupt_init(void) +{ + return (0); +} + +void udelay(unsigned long usec) +{ + unsigned long delay, start, stop; + unsigned long cclk; + cclk = (CONFIG_CCLK_HZ); + + while (usec > 1) { + /* + * how many clock ticks to delay? + * - request(in useconds) * clock_ticks(Hz) / useconds/second + */ + if (usec < 1000) { + delay = (usec * (cclk / 244)) >> 12; + usec = 0; + } else { + delay = (1000 * (cclk / 244)) >> 12; + usec -= 1000; + } + + asm volatile (" %0 = CYCLES;":"=r" (start)); + do { + asm volatile (" %0 = CYCLES; ":"=r" (stop)); + } while (stop - start < delay); + } + + return; +} + +void timer_init(void) +{ + *pTCNTL = 0x1; + *pTSCALE = 0x0; + *pTCOUNT = MAX_TIM_LOAD; + *pTPERIOD = MAX_TIM_LOAD; + *pTCNTL = 0x7; + asm("CSYNC;"); + + timestamp = 0; + last_time = 0; +} + +/* Any network command or flash + * command is started get_timer shall + * be called before TCOUNT gets reset, + * to implement the accurate timeouts. + * + * How ever milliconds doesn't return + * the number that has been elapsed from + * the last reset. + * + * As get_timer is used in the u-boot + * only for timeouts this should be + * sufficient + */ +ulong get_timer(ulong base) +{ + ulong milisec; + + /* Number of clocks elapsed */ + ulong clocks = (MAX_TIM_LOAD - (*pTCOUNT)); + + /** + * Find if the TCOUNT is reset + * timestamp gives the number of times + * TCOUNT got reset + */ + if (clocks < last_time) + timestamp++; + last_time = clocks; + + /* Get the number of milliseconds */ + milisec = clocks / (CONFIG_CCLK_HZ / 1000); + + /** + * Find the number of millisonds + * that got elapsed before this TCOUNT cycle + */ + milisec += timestamp * (MAX_TIM_LOAD / (CONFIG_CCLK_HZ / 1000)); + + return (milisec - base); +} + +void reset_timer (void) +{ + timestamp = 0; +} diff --git a/cpu/bf537/ints.c b/cpu/bf537/ints.c new file mode 100644 index 0000000..f476f14 --- /dev/null +++ b/cpu/bf537/ints.c @@ -0,0 +1,117 @@ +/* + * U-boot - ints.c Interrupt related routines + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on ints.c + * + * Apr18 2003, Changed by HuTao to support interrupt cascading for Blackfin + * drivers + * + * Copyright 1996 Roman Zippel + * Copyright 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca> + * Copyright 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca> + * Copyright 2003 Metrowerks/Motorola + * + * (C) Copyright 2000-2004 + * 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 <linux/stddef.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/traps.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/machdep.h> +#include <asm/setup.h> +#include <asm/blackfin.h> +#include "cpu.h" + +void blackfin_irq_panic(int reason, struct pt_regs *regs) +{ + printf("\n\nException: IRQ 0x%x entered\n", reason); + printf("code=[0x%x], ", (unsigned int)(regs->seqstat & 0x3f)); + printf("stack frame=0x%x, ", (unsigned int)regs); + printf("bad PC=0x%04x\n", (unsigned int)regs->pc); + dump(regs); + printf("Unhandled IRQ or exceptions!\n"); + printf("Please reset the board \n"); +} + +void blackfin_init_IRQ(void) +{ + *(unsigned volatile long *)(SIC_IMASK) = SIC_UNMASK_ALL; + cli(); +#ifndef CONFIG_KGDB + *(unsigned volatile long *)(EVT_EMULATION_ADDR) = 0x0; +#endif + *(unsigned volatile long *)(EVT_NMI_ADDR) = + (unsigned volatile long)evt_nmi; + *(unsigned volatile long *)(EVT_EXCEPTION_ADDR) = + (unsigned volatile long)trap; + *(unsigned volatile long *)(EVT_HARDWARE_ERROR_ADDR) = + (unsigned volatile long)evt_ivhw; + *(unsigned volatile long *)(EVT_RESET_ADDR) = + (unsigned volatile long)evt_rst; + *(unsigned volatile long *)(EVT_TIMER_ADDR) = + (unsigned volatile long)evt_timer; + *(unsigned volatile long *)(EVT_IVG7_ADDR) = + (unsigned volatile long)evt_evt7; + *(unsigned volatile long *)(EVT_IVG8_ADDR) = + (unsigned volatile long)evt_evt8; + *(unsigned volatile long *)(EVT_IVG9_ADDR) = + (unsigned volatile long)evt_evt9; + *(unsigned volatile long *)(EVT_IVG10_ADDR) = + (unsigned volatile long)evt_evt10; + *(unsigned volatile long *)(EVT_IVG11_ADDR) = + (unsigned volatile long)evt_evt11; + *(unsigned volatile long *)(EVT_IVG12_ADDR) = + (unsigned volatile long)evt_evt12; + *(unsigned volatile long *)(EVT_IVG13_ADDR) = + (unsigned volatile long)evt_evt13; + *(unsigned volatile long *)(EVT_IVG14_ADDR) = + (unsigned volatile long)evt_system_call; + *(unsigned volatile long *)(EVT_IVG15_ADDR) = + (unsigned volatile long)evt_soft_int1; + *(volatile unsigned long *)ILAT = 0; + asm("csync;"); + sti(); + *(volatile unsigned long *)IMASK = 0xffbf; + asm("csync;"); +} + +void exception_handle(void) +{ +#if defined (CONFIG_PANIC_HANG) + display_excp(); +#else + udelay(100000); /* allow messages to go out */ + do_reset(NULL, 0, 0, NULL); +#endif +} + +void display_excp(void) +{ + printf("Exception!\n"); +} diff --git a/cpu/bf537/serial.c b/cpu/bf537/serial.c new file mode 100644 index 0000000..dd4f916 --- /dev/null +++ b/cpu/bf537/serial.c @@ -0,0 +1,194 @@ +/* + * U-boot - serial.c Serial driver for BF537 + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on + * bf537_serial.c: Serial driver for BlackFin BF537 internal UART. + * Copyright (c) 2003 Bas Vermeulen <bas@buyways.nl>, + * BuyWays B.V. (www.buyways.nl) + * + * Based heavily on blkfinserial.c + * blkfinserial.c: Serial driver for BlackFin DSP internal USRTs. + * Copyright(c) 2003 Metrowerks <mwaddel@metrowerks.com> + * Copyright(c) 2001 Tony Z. Kou <tonyko@arcturusnetworks.com> + * Copyright(c) 2001-2002 Arcturus Networks Inc. <www.arcturusnetworks.com> + * + * Based on code from 68328 version serial driver imlpementation which was: + * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu> + * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> + * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com> + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/segment.h> +#include <asm/bitops.h> +#include <asm/delay.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include "serial.h" + +unsigned long pll_div_fact; + +void calc_baud(void) +{ + unsigned char i; + int temp; + u_long sclk = get_sclk(); + + for (i = 0; i < sizeof(baud_table) / sizeof(int); i++) { + temp = sclk / (baud_table[i] * 8); + if ((temp & 0x1) == 1) { + temp++; + } + temp = temp / 2; + hw_baud_table[i].dl_high = (temp >> 8) & 0xFF; + hw_baud_table[i].dl_low = (temp) & 0xFF; + } +} + +void serial_setbrg(void) +{ + int i; + DECLARE_GLOBAL_DATA_PTR; + + calc_baud(); + + for (i = 0; i < sizeof(baud_table) / sizeof(int); i++) { + if (gd->baudrate == baud_table[i]) + break; + } + + /* Enable UART */ + *pUART_GCTL |= UART_GCTL_UCEN; + sync(); + + /* Set DLAB in LCR to Access DLL and DLH */ + ACCESS_LATCH; + sync(); + + *pUART_DLL = hw_baud_table[i].dl_low; + sync(); + *pUART_DLH = hw_baud_table[i].dl_high; + sync(); + + /* Clear DLAB in LCR to Access THR RBR IER */ + ACCESS_PORT_IER; + sync(); + + /* Enable ERBFI and ELSI interrupts + * to poll SIC_ISR register*/ + *pUART_IER = UART_IER_ELSI | UART_IER_ERBFI | UART_IER_ETBEI; + sync(); + + /* Set LCR to Word Lengh 8-bit word select */ + *pUART_LCR = UART_LCR_WLS8; + sync(); + + return; +} + +int serial_init(void) +{ + serial_setbrg(); + return (0); +} + +void serial_putc(const char c) +{ + if ((*pUART_LSR) & UART_LSR_TEMT) { + if (c == '\n') + serial_putc('\r'); + + local_put_char(c); + } + + while (!((*pUART_LSR) & UART_LSR_TEMT)) + SYNC_ALL; + + return; +} + +int serial_tstc(void) +{ + if (*pUART_LSR & UART_LSR_DR) + return 1; + else + return 0; +} + +int serial_getc(void) +{ + unsigned short uart_lsr_val, uart_rbr_val; + unsigned long isr_val; + int ret; + + /* Poll for RX Interrupt */ + while (!((isr_val = + *(volatile unsigned long *)SIC_ISR) & IRQ_UART_RX_BIT)) ; + asm("csync;"); + + uart_lsr_val = *pUART_LSR; /* Clear status bit */ + uart_rbr_val = *pUART_RBR; /* getc() */ + + if (isr_val & IRQ_UART_ERROR_BIT) { + ret = -1; + } else { + ret = uart_rbr_val & 0xff; + } + + return ret; +} + +void serial_puts(const char *s) +{ + while (*s) { + serial_putc(*s++); + } +} + +static void local_put_char(char ch) +{ + int flags = 0; + unsigned long isr_val; + + save_and_cli(flags); + + /* Poll for TX Interruput */ + while (!((isr_val = *pSIC_ISR) & IRQ_UART_TX_BIT)) ; + asm("csync;"); + + *pUART_THR = ch; /* putc() */ + + if (isr_val & IRQ_UART_ERROR_BIT) { + printf("?"); + } + + restore_flags(flags); + + return; +} diff --git a/cpu/bf537/serial.h b/cpu/bf537/serial.h new file mode 100644 index 0000000..c9ee3dc --- /dev/null +++ b/cpu/bf537/serial.h @@ -0,0 +1,77 @@ +/* + * U-boot - bf537_serial.h Serial Driver defines + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on + * bf533_serial.h: Definitions for the BlackFin BF533 DSP serial driver. + * Copyright (C) 2003 Bas Vermeulen <bas@buyways.nl> + * BuyWays B.V. (www.buyways.nl) + * + * Based heavily on: + * blkfinserial.h: Definitions for the BlackFin DSP serial driver. + * + * Copyright (C) 2001 Tony Z. Kou tonyko@arcturusnetworks.com + * Copyright (C) 2001 Arcturus Networks Inc. <www.arcturusnetworks.com> + * + * Based on code from 68328serial.c which was: + * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu> + * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> + * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org> + * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com> + * + * (C) Copyright 2000-2004 + * 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 + */ + +#ifndef _Bf537_SERIAL_H +#define _Bf537_SERIAL_H + +#include <linux/config.h> +#include <asm/blackfin.h> + +#define SYNC_ALL __asm__ __volatile__ ("ssync;\n") +#define ACCESS_LATCH *pUART_LCR |= UART_LCR_DLAB; +#define ACCESS_PORT_IER *pUART_LCR &= (~UART_LCR_DLAB); + +void serial_setbrg(void); +static void local_put_char(char ch); +void calc_baud(void); +void serial_setbrg(void); +int serial_init(void); +void serial_putc(const char c); +int serial_tstc(void); +int serial_getc(void); +void serial_puts(const char *s); +static void local_put_char(char ch); + +int baud_table[5] = { 9600, 19200, 38400, 57600, 115200 }; + +struct { + unsigned char dl_high; + unsigned char dl_low; +} hw_baud_table[5]; + +#ifdef CONFIG_STAMP +extern unsigned long pll_div_fact; +#endif + +#endif diff --git a/cpu/bf537/start.S b/cpu/bf537/start.S new file mode 100644 index 0000000..264e9b6 --- /dev/null +++ b/cpu/bf537/start.S @@ -0,0 +1,579 @@ +/* + * U-boot - start.S Startup file of u-boot for BF537 + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on head.S + * Copyright (c) 2003 Metrowerks/Motorola + * Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, + * Kenneth Albanowski <kjahds@kjahds.com>, + * The Silver Hammer Group, Ltd. + * (c) 1995, Dionne & Associates + * (c) 1995, DKG Display Tech. + * + * 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 + */ + +/* + * Note: A change in this file subsequently requires a change in + * board/$(board_name)/config.mk for a valid u-boot.bin + */ + +#define ASSEMBLY + +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> + +.global _stext; +.global __bss_start; +.global start; +.global _start; +.global _rambase; +.global _ramstart; +.global _ramend; +.global _bf533_data_dest; +.global _bf533_data_size; +.global edata; +.global _initialize; +.global _exit; +.global flashdataend; +.global init_sdram; +.global _icache_enable; +.global _dcache_enable; +#if defined(CONFIG_BF537)&&defined(CONFIG_POST) +.global _memory_post_test; +.global _post_flag; +#endif + +#if (BFIN_BOOT_MODE == BF537_UART_BOOT) +#if (CONFIG_CCLK_DIV == 1) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV1 +#endif +#if (CONFIG_CCLK_DIV == 2) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV2 +#endif +#if (CONFIG_CCLK_DIV == 4) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV4 +#endif +#if (CONFIG_CCLK_DIV == 8) +#define CONFIG_CCLK_ACT_DIV CCLK_DIV8 +#endif +#ifndef CONFIG_CCLK_ACT_DIV +#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly +#endif +#endif + +.text +_start: +start: +_stext: + + R0 = 0x32; + SYSCFG = R0; + SSYNC; + + /* As per HW reference manual DAG registers, + * DATA and Address resgister shall be zero'd + * in initialization, after a reset state + */ + r1 = 0; /* Data registers zero'd */ + r2 = 0; + r3 = 0; + r4 = 0; + r5 = 0; + r6 = 0; + r7 = 0; + + p0 = 0; /* Address registers zero'd */ + p1 = 0; + p2 = 0; + p3 = 0; + p4 = 0; + p5 = 0; + + i0 = 0; /* DAG Registers zero'd */ + i1 = 0; + i2 = 0; + i3 = 0; + m0 = 0; + m1 = 0; + m3 = 0; + m3 = 0; + l0 = 0; + l1 = 0; + l2 = 0; + l3 = 0; + b0 = 0; + b1 = 0; + b2 = 0; + b3 = 0; + + /* Set loop counters to zero, to make sure that + * hw loops are disabled. + */ + r0 = 0; + lc0 = r0; + lc1 = r0; + + SSYNC; + + /* Check soft reset status */ + p0.h = SWRST >> 16; + p0.l = SWRST & 0xFFFF; + r0.l = w[p0]; + + cc = bittst(r0, 15); + if !cc jump no_soft_reset; + + /* Clear Soft reset */ + r0 = 0x0000; + w[p0] = r0; + ssync; + +no_soft_reset: + nop; + + /* Clear EVT registers */ + p0.h = (EVT_EMULATION_ADDR >> 16); + p0.l = (EVT_EMULATION_ADDR & 0xFFFF); + p0 += 8; + p1 = 14; + r1 = 0; + LSETUP(4,4) lc0 = p1; + [ p0 ++ ] = r1; + +#if (BFIN_BOOT_MODE != BF537_SPI_MASTER_BOOT) + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; + w[p0] = r0.l; + SSYNC; +#endif + +#if (BFIN_BOOT_MODE == BF537_UART_BOOT) + + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; + w[p0] = r0.l; + SSYNC; + + /* + * PLL_LOCKCNT - how many SCLK Cycles to delay while PLL becomes stable + */ + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + /* + * Put SDRAM in self-refresh, incase anything is running + */ + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + /* + * Set PLL_CTL with the value that we calculate in R0 + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over, */ + r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +check_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump check_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; +#endif + + /* + * We now are running at speed, time to set the Async mem bank wait states + * This will speed up execution, since we are normally running from FLASH. + * we need to read MAC address from FLASH + */ + p2.h = (EBIU_AMBCTL1 >> 16); + p2.l = (EBIU_AMBCTL1 & 0xFFFF); + r0.h = (AMBCTL1VAL >> 16); + r0.l = (AMBCTL1VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMBCTL0 >> 16); + p2.l = (EBIU_AMBCTL0 & 0xFFFF); + r0.h = (AMBCTL0VAL >> 16); + r0.l = (AMBCTL0VAL & 0xFFFF); + [p2] = r0; + ssync; + + p2.h = (EBIU_AMGCTL >> 16); + p2.l = (EBIU_AMGCTL & 0xffff); + r0 = AMGCTLVAL; + w[p2] = r0; + ssync; + +#if ((BFIN_BOOT_MODE != BF537_SPI_MASTER_BOOT) && (BFIN_BOOT_MODE != BF537_UART_BOOT)) + sp.l = (0xffb01000 & 0xFFFF); + sp.h = (0xffb01000 >> 16); + + call init_sdram; +#endif + + +#if defined(CONFIG_BF537)&&defined(CONFIG_POST) + /* DMA POST code to Hi of L1 SRAM */ +postcopy: + /* P1 Points to the beginning of SYSTEM MMR Space */ + P1.H = hi(SYSMMR_BASE); + P1.L = lo(SYSMMR_BASE); + + R0.H = _text_l1; + R0.L = _text_l1; + R1.H = _etext_l1; + R1.L = _etext_l1; + R2 = R1 - R0; /* Count */ + R0.H = _etext; + R0.L = _etext; + R1.H = (CFG_MONITOR_BASE >> 16); + R1.L = (CFG_MONITOR_BASE & 0xFFFF); + R0 = R0 - R1; + R1.H = (CFG_FLASH_BASE >> 16); + R1.L = (CFG_FLASH_BASE & 0xFFFF); + R0 = R0 + R1; /* Source Address */ + R1.H = hi(L1_ISRAM); /* Destination Address (high) */ + R1.L = lo(L1_ISRAM); /* Destination Address (low) */ + R3.L = DMAEN; /* Source DMAConfig Value (8-bit words) */ + /* Destination DMAConfig Value (8-bit words) */ + R4.L = (DI_EN | WNR | DMAEN); + + R6 = 0x1 (Z); + W[P1+OFFSET_(MDMA_S0_X_MODIFY)] = R6; /* Source Modify = 1 */ + W[P1+OFFSET_(MDMA_D0_X_MODIFY)] = R6; /* Destination Modify = 1 */ + + [P1+OFFSET_(MDMA_S0_START_ADDR)] = R0; /* Set Source Base Address */ + W[P1+OFFSET_(MDMA_S0_X_COUNT)] = R2; /* Set Source Count */ + /* Set Source DMAConfig = DMA Enable, + Memory Read, 8-Bit Transfers, 1-D DMA, Flow - Stop */ + W[P1+OFFSET_(MDMA_S0_CONFIG)] = R3; + + [P1+OFFSET_(MDMA_D0_START_ADDR)] = R1; /* Set Destination Base Address */ + W[P1+OFFSET_(MDMA_D0_X_COUNT)] = R2; /* Set Destination Count */ + /* Set Destination DMAConfig = DMA Enable, + Memory Write, 8-Bit Transfers, 1-D DMA, Flow - Stop, IOC */ + W[P1+OFFSET_(MDMA_D0_CONFIG)] = R4; + +POST_DMA_DONE: + p0.h = hi(MDMA_D0_IRQ_STATUS); + p0.l = lo(MDMA_D0_IRQ_STATUS); + R0 = W[P0](Z); + CC = BITTST(R0, 0); + if ! CC jump POST_DMA_DONE + + R0 = 0x1; + W[P1+OFFSET_(MDMA_D0_IRQ_STATUS)] = R0; /* Write 1 to clear DMA interrupt */ + + /* DMA POST data to Hi of L1 SRAM */ + R0.H = _rodata_l1; + R0.L = _rodata_l1; + R1.H = _erodata_l1; + R1.L = _erodata_l1; + R2 = R1 - R0; /* Count */ + R0.H = _erodata; + R0.L = _erodata; + R1.H = (CFG_MONITOR_BASE >> 16); + R1.L = (CFG_MONITOR_BASE & 0xFFFF); + R0 = R0 - R1; + R1.H = (CFG_FLASH_BASE >> 16); + R1.L = (CFG_FLASH_BASE & 0xFFFF); + R0 = R0 + R1; /* Source Address */ + R1.H = hi(DATA_BANKB_SRAM); /* Destination Address (high) */ + R1.L = lo(DATA_BANKB_SRAM); /* Destination Address (low) */ + R3.L = DMAEN; /* Source DMAConfig Value (8-bit words) */ + R4.L = (DI_EN | WNR | DMAEN); /* Destination DMAConfig Value (8-bit words) */ + + R6 = 0x1 (Z); + W[P1+OFFSET_(MDMA_S0_X_MODIFY)] = R6; /* Source Modify = 1 */ + W[P1+OFFSET_(MDMA_D0_X_MODIFY)] = R6; /* Destination Modify = 1 */ + + [P1+OFFSET_(MDMA_S0_START_ADDR)] = R0; /* Set Source Base Address */ + W[P1+OFFSET_(MDMA_S0_X_COUNT)] = R2; /* Set Source Count */ + /* Set Source DMAConfig = DMA Enable, + Memory Read, 8-Bit Transfers, 1-D DMA, Flow - Stop */ + W[P1+OFFSET_(MDMA_S0_CONFIG)] = R3; + + [P1+OFFSET_(MDMA_D0_START_ADDR)] = R1; /* Set Destination Base Address */ + W[P1+OFFSET_(MDMA_D0_X_COUNT)] = R2; /* Set Destination Count */ + /* Set Destination DMAConfig = DMA Enable, + Memory Write, 8-Bit Transfers, 1-D DMA, Flow - Stop, IOC */ + W[P1+OFFSET_(MDMA_D0_CONFIG)] = R4; + +POST_DATA_DMA_DONE: + p0.h = hi(MDMA_D0_IRQ_STATUS); + p0.l = lo(MDMA_D0_IRQ_STATUS); + R0 = W[P0](Z); + CC = BITTST(R0, 0); + if ! CC jump POST_DATA_DMA_DONE + + R0 = 0x1; + W[P1+OFFSET_(MDMA_D0_IRQ_STATUS)] = R0; /* Write 1 to clear DMA interrupt */ + + p0.l = _memory_post_test; + p0.h = _memory_post_test; + r0 = 0x0; + call (p0); + r7 = r0; /* save return value */ + + call init_sdram; +#endif + + /* relocate into to RAM */ + call get_pc; +offset: + r2.l = offset; + r2.h = offset; + r3.l = start; + r3.h = start; + r1 = r2 - r3; + + r0 = r0 - r1; + p1 = r0; + + p2.l = (CFG_MONITOR_BASE & 0xffff); + p2.h = (CFG_MONITOR_BASE >> 16); + + p3 = 0x04; + p4.l = ((CFG_MONITOR_BASE + CFG_MONITOR_LEN) & 0xffff); + p4.h = ((CFG_MONITOR_BASE + CFG_MONITOR_LEN) >> 16); +loop1: + r1 = [p1 ++ p3]; + [p2 ++ p3] = r1; + cc=p2==p4; + if !cc jump loop1; + /* + * configure STACK + */ + r0.h = (CONFIG_STACKBASE >> 16); + r0.l = (CONFIG_STACKBASE & 0xFFFF); + sp = r0; + fp = sp; + + /* + * This next section keeps the processor in supervisor mode + * during kernel boot. Switches to user mode at end of boot. + * See page 3-9 of Hardware Reference manual for documentation. + */ + + /* To keep ourselves in the supervisor mode */ + p0.l = (EVT_IVG15_ADDR & 0xFFFF); + p0.h = (EVT_IVG15_ADDR >> 16); + + p1.l = _real_start; + p1.h = _real_start; + [p0] = p1; + + p0.l = (IMASK & 0xFFFF); + p0.h = (IMASK >> 16); + r0.l = LO(IVG15_POS); + r0.h = HI(IVG15_POS); + [p0] = r0; + raise 15; + p0.l = WAIT_HERE; + p0.h = WAIT_HERE; + reti = p0; + rti; + +WAIT_HERE: + jump WAIT_HERE; + +.global _real_start; +_real_start: + [ -- sp ] = reti; + +#ifdef CONFIG_BF537 +/* Initialise General-Purpose I/O Modules on BF537 + * Rev 0.0 Anomaly 05000212 - PORTx_FER, + * PORT_MUX Registers Do Not accept "writes" correctly + */ + p0.h = hi(PORTF_FER); + p0.l = lo(PORTF_FER); + R0.L = W[P0]; /* Read */ + nop; + nop; + nop; + ssync; + R0 = 0x000F(Z); + W[P0] = R0.L; /* Write */ + nop; + nop; + nop; + ssync; + W[P0] = R0.L; /* Enable peripheral function of PORTF for UART0 and UART1 */ + nop; + nop; + nop; + ssync; + + p0.h = hi(PORTH_FER); + p0.l = lo(PORTH_FER); + R0.L = W[P0]; /* Read */ + nop; + nop; + nop; + ssync; + R0 = 0xFFFF(Z); + W[P0] = R0.L; /* Write */ + nop; + nop; + nop; + ssync; + W[P0] = R0.L; /* Enable peripheral function of PORTH for MAC */ + nop; + nop; + nop; + ssync; + +#endif + + /* DMA reset code to Hi of L1 SRAM */ +copy: + P1.H = hi(SYSMMR_BASE); /* P1 Points to the beginning of SYSTEM MMR Space */ + P1.L = lo(SYSMMR_BASE); + + R0.H = reset_start; /* Source Address (high) */ + R0.L = reset_start; /* Source Address (low) */ + R1.H = reset_end; + R1.L = reset_end; + R2 = R1 - R0; /* Count */ + R1.H = hi(L1_ISRAM); /* Destination Address (high) */ + R1.L = lo(L1_ISRAM); /* Destination Address (low) */ + R3.L = DMAEN; /* Source DMAConfig Value (8-bit words) */ + R4.L = (DI_EN | WNR | DMAEN); /* Destination DMAConfig Value (8-bit words) */ + +DMA: + R6 = 0x1 (Z); + W[P1+OFFSET_(MDMA_S0_X_MODIFY)] = R6; /* Source Modify = 1 */ + W[P1+OFFSET_(MDMA_D0_X_MODIFY)] = R6; /* Destination Modify = 1 */ + + [P1+OFFSET_(MDMA_S0_START_ADDR)] = R0; /* Set Source Base Address */ + W[P1+OFFSET_(MDMA_S0_X_COUNT)] = R2; /* Set Source Count */ + /* Set Source DMAConfig = DMA Enable, + Memory Read, 8-Bit Transfers, 1-D DMA, Flow - Stop */ + W[P1+OFFSET_(MDMA_S0_CONFIG)] = R3; + + [P1+OFFSET_(MDMA_D0_START_ADDR)] = R1; /* Set Destination Base Address */ + W[P1+OFFSET_(MDMA_D0_X_COUNT)] = R2; /* Set Destination Count */ + /* Set Destination DMAConfig = DMA Enable, + Memory Write, 8-Bit Transfers, 1-D DMA, Flow - Stop, IOC */ + W[P1+OFFSET_(MDMA_D0_CONFIG)] = R4; + +WAIT_DMA_DONE: + p0.h = hi(MDMA_D0_IRQ_STATUS); + p0.l = lo(MDMA_D0_IRQ_STATUS); + R0 = W[P0](Z); + CC = BITTST(R0, 0); + if ! CC jump WAIT_DMA_DONE + + R0 = 0x1; + W[P1+OFFSET_(MDMA_D0_IRQ_STATUS)] = R0; /* Write 1 to clear DMA interrupt */ + + /* Initialize BSS Section with 0 s */ + p1.l = __bss_start; + p1.h = __bss_start; + p2.l = _end; + p2.h = _end; + r1 = p1; + r2 = p2; + r3 = r2 - r1; + r3 = r3 >> 2; + p3 = r3; + lsetup (_clear_bss, _clear_bss_end ) lc1 = p3; + CC = p2<=p1; + if CC jump _clear_bss_skip; + r0 = 0; +_clear_bss: +_clear_bss_end: + [p1++] = r0; +_clear_bss_skip: + +#if defined(CONFIG_BF537)&&defined(CONFIG_POST) + p0.l = _post_flag; + p0.h = _post_flag; + r0 = r7; + [p0] = r0; +#endif + + p0.l = _start1; + p0.h = _start1; + jump (p0); + +reset_start: + p0.h = WDOG_CNT >> 16; + p0.l = WDOG_CNT & 0xffff; + r0 = 0x0010; + w[p0] = r0; + p0.h = WDOG_CTL >> 16; + p0.l = WDOG_CTL & 0xffff; + r0 = 0x0000; + w[p0] = r0; +reset_wait: + jump reset_wait; + +reset_end: + nop; + +_exit: + jump.s _exit; +get_pc: + r0 = rets; + rts; diff --git a/cpu/bf537/start1.S b/cpu/bf537/start1.S new file mode 100644 index 0000000..72cfafb --- /dev/null +++ b/cpu/bf537/start1.S @@ -0,0 +1,38 @@ +/* + * U-boot - start1.S Code running out of RAM after relocation + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * 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 + */ + +#define ASSEMBLY +#include <linux/config.h> +#include <config.h> +#include <asm/blackfin.h> + +.global start1; +.global _start1; + +.text +_start1: +start1: + sp += -12; + call _board_init_f; + sp += 12; diff --git a/cpu/bf537/traps.c b/cpu/bf537/traps.c new file mode 100644 index 0000000..994ece8 --- /dev/null +++ b/cpu/bf537/traps.c @@ -0,0 +1,241 @@ +/* + * U-boot - traps.c Routines related to interrupts and exceptions + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * This file is based on + * No original Copyright holder listed, + * Probabily original (C) Roman Zippel (assigned DJD, 1999) + * + * Copyright 2003 Metrowerks - for Blackfin + * Copyright 2000-2001 Lineo, Inc. D. Jeff Dionne <jeff@lineo.ca> + * Copyright 1999-2000 D. Jeff Dionne, <jeff@uclinux.org> + * + * (C) Copyright 2000-2004 + * 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 <linux/types.h> +#include <asm/errno.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/traps.h> +#include <asm/page.h> +#include <asm/machdep.h> +#include "cpu.h" +#include <asm/arch/anomaly.h> +#include <asm/cplb.h> +#include <asm/io.h> + +void init_IRQ(void) +{ + blackfin_init_IRQ(); + return; +} + +void process_int(unsigned long vec, struct pt_regs *fp) +{ + printf("interrupt\n"); + return; +} + +extern unsigned int icplb_table[page_descriptor_table_size][2]; +extern unsigned int dcplb_table[page_descriptor_table_size][2]; + +unsigned long last_cplb_fault_retx; + +static unsigned int cplb_sizes[4] = + { 1024, 4 * 1024, 1024 * 1024, 4 * 1024 * 1024 }; + +void trap_c(struct pt_regs *regs) +{ + unsigned int addr; + unsigned long trapnr = (regs->seqstat) & SEQSTAT_EXCAUSE; + unsigned int i, j, size, *I0, *I1; + unsigned short data = 0; + + switch (trapnr) { + /* 0x26 - Data CPLB Miss */ + case VEC_CPLB_M: + +#ifdef ANOMALY_05000261 + /* + * Work around an anomaly: if we see a new DCPLB fault, + * return without doing anything. Then, + * if we get the same fault again, handle it. + */ + addr = last_cplb_fault_retx; + last_cplb_fault_retx = regs->retx; + printf("this time, curr = 0x%08x last = 0x%08x\n", + addr, last_cplb_fault_retx); + if (addr != last_cplb_fault_retx) + goto trap_c_return; +#endif + data = 1; + + case VEC_CPLB_I_M: + + if (data) { + addr = *pDCPLB_FAULT_ADDR; + } else { + addr = *pICPLB_FAULT_ADDR; + } + for (i = 0; i < page_descriptor_table_size; i++) { + if (data) { + size = cplb_sizes[dcplb_table[i][1] >> 16]; + j = dcplb_table[i][0]; + } else { + size = cplb_sizes[icplb_table[i][1] >> 16]; + j = icplb_table[i][0]; + } + if ((j <= addr) && ((j + size) > addr)) { + debug("found %i 0x%08x\n", i, j); + break; + } + } + if (i == page_descriptor_table_size) { + printf("something is really wrong\n"); + do_reset(NULL, 0, 0, NULL); + } + + /* Turn the cache off */ + if (data) { + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL &= + ~(ACACHE_BCACHE | ENDCPLB | PORT_PREF0); + sync(); + } else { + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL &= ~(IMC | ENICPLB); + sync(); + } + + if (data) { + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + } else { + I0 = (unsigned int *)ICPLB_ADDR0; + I1 = (unsigned int *)ICPLB_DATA0; + } + + j = 0; + while (*I1 & CPLB_LOCK) { + debug("skipping %i %08p - %08x\n", j, I1, *I1); + *I0++; + *I1++; + j++; + } + + debug("remove %i 0x%08x 0x%08x\n", j, *I0, *I1); + + for (; j < 15; j++) { + debug("replace %i 0x%08x 0x%08x\n", j, I0, I0 + 1); + *I0++ = *(I0 + 1); + *I1++ = *(I1 + 1); + } + + if (data) { + *I0 = dcplb_table[i][0]; + *I1 = dcplb_table[i][1]; + I0 = (unsigned int *)DCPLB_ADDR0; + I1 = (unsigned int *)DCPLB_DATA0; + } else { + *I0 = icplb_table[i][0]; + *I1 = icplb_table[i][1]; + I0 = (unsigned int *)ICPLB_ADDR0; + I1 = (unsigned int *)ICPLB_DATA0; + } + + for (j = 0; j < 16; j++) { + debug("%i 0x%08x 0x%08x\n", j, *I0++, *I1++); + } + + /* Turn the cache back on */ + if (data) { + j = *(unsigned int *)DMEM_CONTROL; + sync(); + asm(" .align 8; "); + *(unsigned int *)DMEM_CONTROL = + ACACHE_BCACHE | ENDCPLB | PORT_PREF0 | j; + sync(); + } else { + sync(); + asm(" .align 8; "); + *(unsigned int *)IMEM_CONTROL = IMC | ENICPLB; + sync(); + } + + break; + default: + /* All traps come here */ + printf("code=[0x%x], ", (unsigned int)(regs->seqstat & 0x3f)); + printf("stack frame=0x%x, ", (unsigned int)regs); + printf("bad PC=0x%04x\n", (unsigned int)regs->pc); + dump(regs); + printf("\n\n"); + + printf("Unhandled IRQ or exceptions!\n"); + printf("Please reset the board \n"); + do_reset(NULL, 0, 0, NULL); + } + +trap_c_return: + return; + +} + +void dump(struct pt_regs *fp) +{ + debug("RETE: %08lx RETN: %08lx RETX: %08lx RETS: %08lx\n", + fp->rete, fp->retn, fp->retx, fp->rets); + debug("IPEND: %04lx SYSCFG: %04lx\n", fp->ipend, fp->syscfg); + debug("SEQSTAT: %08lx SP: %08lx\n", (long)fp->seqstat, (long)fp); + debug("R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n", + fp->r0, fp->r1, fp->r2, fp->r3); + debug("R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n", + fp->r4, fp->r5, fp->r6, fp->r7); + debug("P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n", + fp->p0, fp->p1, fp->p2, fp->p3); + debug("P4: %08lx P5: %08lx FP: %08lx\n", + fp->p4, fp->p5, fp->fp); + debug("A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n", + fp->a0w, fp->a0x, fp->a1w, fp->a1x); + + debug("LB0: %08lx LT0: %08lx LC0: %08lx\n", + fp->lb0, fp->lt0, fp->lc0); + debug("LB1: %08lx LT1: %08lx LC1: %08lx\n", + fp->lb1, fp->lt1, fp->lc1); + debug("B0: %08lx L0: %08lx M0: %08lx I0: %08lx\n", + fp->b0, fp->l0, fp->m0, fp->i0); + debug("B1: %08lx L1: %08lx M1: %08lx I1: %08lx\n", + fp->b1, fp->l1, fp->m1, fp->i1); + debug("B2: %08lx L2: %08lx M2: %08lx I2: %08lx\n", + fp->b2, fp->l2, fp->m2, fp->i2); + debug("B3: %08lx L3: %08lx M3: %08lx I3: %08lx\n", + fp->b3, fp->l3, fp->m3, fp->i3); + + debug("DCPLB_FAULT_ADDR=%p\n", *pDCPLB_FAULT_ADDR); + debug("ICPLB_FAULT_ADDR=%p\n", *pICPLB_FAULT_ADDR); + +} diff --git a/cpu/bf537/video.c b/cpu/bf537/video.c new file mode 100644 index 0000000..3ff0151 --- /dev/null +++ b/cpu/bf537/video.c @@ -0,0 +1,194 @@ +/* + * (C) Copyright 2000 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * (C) Copyright 2002 + * Wolfgang Denk, wd@denx.de + * (C) Copyright 2006 + * Aubrey Li, aubrey.li@analog.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 <stdarg.h> +#include <common.h> +#include <config.h> +#include <asm/blackfin.h> +#include <i2c.h> +#include <linux/types.h> +#include <devices.h> + +#ifdef CONFIG_VIDEO +#define NTSC_FRAME_ADDR 0x06000000 +#include "video.h" + +/* NTSC OUTPUT SIZE 720 * 240 */ +#define VERTICAL 2 +#define HORIZONTAL 4 + +int is_vblank_line(const int line) +{ + /* + * This array contains a single bit for each line in + * an NTSC frame. + */ + if ((line <= 18) || (line >= 264 && line <= 281) || (line == 528)) + return true; + + return false; +} + +int NTSC_framebuffer_init(char *base_address) +{ + const int NTSC_frames = 1; + const int NTSC_lines = 525; + char *dest = base_address; + int frame_num, line_num; + + for (frame_num = 0; frame_num < NTSC_frames; ++frame_num) { + for (line_num = 1; line_num <= NTSC_lines; ++line_num) { + unsigned int code; + int offset = 0; + int i; + + if (is_vblank_line(line_num)) + offset++; + + if (line_num > 266 || line_num < 3) + offset += 2; + + /* Output EAV code */ + code = SystemCodeMap[offset].EAV; + write_dest_byte((char)(code >> 24) & 0xff); + write_dest_byte((char)(code >> 16) & 0xff); + write_dest_byte((char)(code >> 8) & 0xff); + write_dest_byte((char)(code) & 0xff); + + /* Output horizontal blanking */ + for (i = 0; i < 67 * 2; ++i) { + write_dest_byte(0x80); + write_dest_byte(0x10); + } + + /* Output SAV */ + code = SystemCodeMap[offset].SAV; + write_dest_byte((char)(code >> 24) & 0xff); + write_dest_byte((char)(code >> 16) & 0xff); + write_dest_byte((char)(code >> 8) & 0xff); + write_dest_byte((char)(code) & 0xff); + + /* Output empty horizontal data */ + for (i = 0; i < 360 * 2; ++i) { + write_dest_byte(0x80); + write_dest_byte(0x10); + } + } + } + + return dest - base_address; +} + +void fill_frame(char *Frame, int Value) +{ + int *OddPtr32; + int OddLine; + int *EvenPtr32; + int EvenLine; + int i; + int *data; + int m, n; + + /* fill odd and even frames */ + for (OddLine = 22, EvenLine = 285; OddLine < 263; OddLine++, EvenLine++) { + OddPtr32 = (int *)((Frame + (OddLine * 1716)) + 276); + EvenPtr32 = (int *)((Frame + (EvenLine * 1716)) + 276); + for (i = 0; i < 360; i++, OddPtr32++, EvenPtr32++) { + *OddPtr32 = Value; + *EvenPtr32 = Value; + } + } + + for (m = 0; m < VERTICAL; m++) { + data = (int *)u_boot_logo.data; + for (OddLine = (22 + m), EvenLine = (285 + m); + OddLine < (u_boot_logo.height * VERTICAL) + (22 + m); + OddLine += VERTICAL, EvenLine += VERTICAL) { + OddPtr32 = (int *)((Frame + ((OddLine) * 1716)) + 276); + EvenPtr32 = + (int *)((Frame + ((EvenLine) * 1716)) + 276); + for (i = 0; i < u_boot_logo.width / 2; i++) { + /* enlarge one pixel to m x n */ + for (n = 0; n < HORIZONTAL; n++) { + *OddPtr32++ = *data; + *EvenPtr32++ = *data; + } + data++; + } + } + } +} + +void video_putc(const char c) +{ +} + +void video_puts(const char *s) +{ +} + +static int video_init(void) +{ + char *NTSCFrame; + NTSCFrame = (char *)NTSC_FRAME_ADDR; + NTSC_framebuffer_init(NTSCFrame); + fill_frame(NTSCFrame, BLUE); + + *pPPI_CONTROL = 0x0082; + *pPPI_FRAME = 0x020D; + + *pDMA0_START_ADDR = NTSCFrame; + *pDMA0_X_COUNT = 0x035A; + *pDMA0_X_MODIFY = 0x0002; + *pDMA0_Y_COUNT = 0x020D; + *pDMA0_Y_MODIFY = 0x0002; + *pDMA0_CONFIG = 0x1015; + *pPPI_CONTROL = 0x0083; + return 0; +} + +int drv_video_init(void) +{ + int error, devices = 1; + + device_t videodev; + + video_init(); /* Video initialization */ + + memset(&videodev, 0, sizeof(videodev)); + + strcpy(videodev.name, "video"); + videodev.ext = DEV_EXT_VIDEO; /* Video extensions */ + videodev.flags = DEV_FLAGS_OUTPUT; /* Output only */ + videodev.putc = video_putc; /* 'putc' function */ + videodev.puts = video_puts; /* 'puts' function */ + + error = device_register(&videodev); + + return (error == 0) ? devices : error; +} +#endif diff --git a/cpu/bf537/video.h b/cpu/bf537/video.h new file mode 100644 index 0000000..a43553f --- /dev/null +++ b/cpu/bf537/video.h @@ -0,0 +1,25 @@ +#include <video_logo.h> +#define write_dest_byte(val) {*dest++=val;} +#define BLACK (0x01800180) /* black pixel pattern */ +#define BLUE (0x296E29F0) /* blue pixel pattern */ +#define RED (0x51F0515A) /* red pixel pattern */ +#define MAGENTA (0x6ADE6ACA) /* magenta pixel pattern*/ +#define GREEN (0x91229136) /* green pixel pattern */ +#define CYAN (0xAA10AAA6) /* cyan pixel pattern */ +#define YELLOW (0xD292D210) /* yellow pixel pattern */ +#define WHITE (0xFE80FE80) /* white pixel pattern */ + +#define true 1 +#define false 0 + +typedef struct { + unsigned int SAV; + unsigned int EAV; +} SystemCodeType; + +const SystemCodeType SystemCodeMap[4] = { + {0xFF000080, 0xFF00009D}, + {0xFF0000AB, 0xFF0000B6}, + {0xFF0000C7, 0xFF0000DA}, + {0xFF0000EC, 0xFF0000F1} +}; |