X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=arch%2Fblackfin%2Fkernel%2Fsetup.c;h=ea4f60978c6642aacca3e34af310521d0b245965;hb=5b04f271fe49bb7adb061de454d383c027a18de0;hp=2f156bfc2b2ce6c330b72844264db90e360c6306;hpb=856783b37a958086c83ea44544d366affd0c2c4b;p=safe%2Fjmp%2Flinux-2.6 diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 2f156bf..ea4f609 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -1,30 +1,11 @@ /* - * File: arch/blackfin/kernel/setup.c - * Based on: - * Author: + * arch/blackfin/kernel/setup.c * - * Created: - * Description: + * Copyright 2004-2006 Analog Devices Inc. * - * Modified: - * Copyright 2004-2006 Analog Devices Inc. + * Enter bugs at http://blackfin.uclinux.org/ * - * Bugs: Enter bugs at http://blackfin.uclinux.org/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see the file COPYING, or write - * to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Licensed under the GPL-2 or later. */ #include @@ -48,9 +29,13 @@ #include #include +static DEFINE_PER_CPU(struct cpu, cpu_devices); + u16 _bfin_swrst; +EXPORT_SYMBOL(_bfin_swrst); unsigned long memory_start, memory_end, physical_mem_end; +unsigned long _rambase, _ramstart, _ramend; unsigned long reserved_mem_dcache_on; unsigned long reserved_mem_icache_on; EXPORT_SYMBOL(memory_start); @@ -67,6 +52,8 @@ EXPORT_SYMBOL(mtd_size); #endif char __initdata command_line[COMMAND_LINE_SIZE]; +void __initdata *init_retx, *init_saved_retx, *init_saved_seqstat, + *init_saved_icplb_fault_addr, *init_saved_dcplb_fault_addr; /* boot memmap, for parsing "memmap=" */ #define BFIN_MEMMAP_MAX 128 /* number of entries in bfin_memmap */ @@ -91,10 +78,10 @@ static struct change_member *change_point[2*BFIN_MEMMAP_MAX] __initdata; static struct bfin_memmap_entry *overlap_list[BFIN_MEMMAP_MAX] __initdata; static struct bfin_memmap_entry new_map[BFIN_MEMMAP_MAX] __initdata; -void __init bf53x_cache_init(void) +void __init bfin_cache_init(void) { #if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE) - generate_cpl_tables(); + generate_cplb_tables(); #endif #ifdef CONFIG_BFIN_ICACHE @@ -114,15 +101,16 @@ void __init bf53x_cache_init(void) #endif } -void __init bf53x_relocate_l1_mem(void) +void __init bfin_relocate_l1_mem(void) { unsigned long l1_code_length; unsigned long l1_data_a_length; unsigned long l1_data_b_length; + unsigned long l2_length; l1_code_length = _etext_l1 - _stext_l1; if (l1_code_length > L1_CODE_LENGTH) - l1_code_length = L1_CODE_LENGTH; + panic("L1 Instruction SRAM Overflow\n"); /* cannot complain as printk is not available as yet. * But we can continue booting and complain later! */ @@ -132,19 +120,27 @@ void __init bf53x_relocate_l1_mem(void) l1_data_a_length = _ebss_l1 - _sdata_l1; if (l1_data_a_length > L1_DATA_A_LENGTH) - l1_data_a_length = L1_DATA_A_LENGTH; + panic("L1 Data SRAM Bank A Overflow\n"); /* Copy _sdata_l1 to _ebss_l1 to L1 data bank A SRAM */ dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length); l1_data_b_length = _ebss_b_l1 - _sdata_b_l1; if (l1_data_b_length > L1_DATA_B_LENGTH) - l1_data_b_length = L1_DATA_B_LENGTH; + panic("L1 Data SRAM Bank B Overflow\n"); /* Copy _sdata_b_l1 to _ebss_b_l1 to L1 data bank B SRAM */ dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length + l1_data_a_length, l1_data_b_length); + if (L2_LENGTH != 0) { + l2_length = _ebss_l2 - _stext_l2; + if (l2_length > L2_LENGTH) + panic("L2 SRAM Overflow\n"); + + /* Copy _stext_l2 to _edata_l2 to L2 SRAM */ + dma_memcpy(_stext_l2, _l2_lma_start, l2_length); + } } /* add_memory_region to memmap */ @@ -424,8 +420,12 @@ static __init void parse_cmdline_early(char *cmdline_p) */ static __init void memory_setup(void) { +#ifdef CONFIG_MTD_UCLINUX + unsigned long mtd_phys = 0; +#endif + _rambase = (unsigned long)_stext; - _ramstart = (unsigned long)__bss_stop; + _ramstart = (unsigned long)_end; if (DMA_UNCACHED_REGION > (_ramend - _ramstart)) { console_init(); @@ -487,7 +487,7 @@ static __init void memory_setup(void) } /* Relocate MTD image to the top of memory after the uncached memory area */ - dma_memcpy((char *)memory_end, __bss_stop, mtd_size); + dma_memcpy((char *)memory_end, _end, mtd_size); memory_mtd_start = memory_end; _ebss = memory_mtd_start; /* define _ebss for compatible */ @@ -526,13 +526,14 @@ static __init void memory_setup(void) printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20); printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20); - printk( KERN_INFO "Memory map:\n" + printk(KERN_INFO "Memory map:\n" + KERN_INFO " fixedcode = 0x%p-0x%p\n" KERN_INFO " text = 0x%p-0x%p\n" KERN_INFO " rodata = 0x%p-0x%p\n" + KERN_INFO " bss = 0x%p-0x%p\n" KERN_INFO " data = 0x%p-0x%p\n" KERN_INFO " stack = 0x%p-0x%p\n" KERN_INFO " init = 0x%p-0x%p\n" - KERN_INFO " bss = 0x%p-0x%p\n" KERN_INFO " available = 0x%p-0x%p\n" #ifdef CONFIG_MTD_UCLINUX KERN_INFO " rootfs = 0x%p-0x%p\n" @@ -540,14 +541,15 @@ static __init void memory_setup(void) #if DMA_UNCACHED_REGION > 0 KERN_INFO " DMA Zone = 0x%p-0x%p\n" #endif - , _stext, _etext, + , (void *)FIXED_CODE_START, (void *)FIXED_CODE_END, + _stext, _etext, __start_rodata, __end_rodata, + __bss_start, __bss_stop, _sdata, _edata, (void *)&init_thread_union, (void *)((int)(&init_thread_union) + 0x2000), - __init_begin, __init_end, - __bss_start, __bss_stop, - (void *)_ramstart, (void *)memory_end + __init_begin, __init_end, + (void *)_ramstart, (void *)memory_end #ifdef CONFIG_MTD_UCLINUX , (void *)memory_mtd_start, (void *)(memory_mtd_start + mtd_size) #endif @@ -557,11 +559,38 @@ static __init void memory_setup(void) ); } +/* + * Find the lowest, highest page frame number we have available + */ +void __init find_min_max_pfn(void) +{ + int i; + + max_pfn = 0; + min_low_pfn = memory_end; + + for (i = 0; i < bfin_memmap.nr_map; i++) { + unsigned long start, end; + /* RAM? */ + if (bfin_memmap.map[i].type != BFIN_MEMMAP_RAM) + continue; + start = PFN_UP(bfin_memmap.map[i].addr); + end = PFN_DOWN(bfin_memmap.map[i].addr + + bfin_memmap.map[i].size); + if (start >= end) + continue; + if (end > max_pfn) + max_pfn = end; + if (start < min_low_pfn) + min_low_pfn = start; + } +} + static __init void setup_bootmem_allocator(void) { int bootmap_size; int i; - unsigned long min_pfn, max_pfn; + unsigned long start_pfn, end_pfn; unsigned long curr_pfn, last_pfn, size; /* mark memory between memory_start and memory_end usable */ @@ -571,8 +600,19 @@ static __init void setup_bootmem_allocator(void) sanitize_memmap(bfin_memmap.map, &bfin_memmap.nr_map); print_memory_map("boot memmap"); - min_pfn = PAGE_OFFSET >> PAGE_SHIFT; - max_pfn = memory_end >> PAGE_SHIFT; + /* intialize globals in linux/bootmem.h */ + find_min_max_pfn(); + /* pfn of the last usable page frame */ + if (max_pfn > memory_end >> PAGE_SHIFT) + max_pfn = memory_end >> PAGE_SHIFT; + /* pfn of last page frame directly mapped by kernel */ + max_low_pfn = max_pfn; + /* pfn of the first usable page frame after kernel image*/ + if (min_low_pfn < memory_start >> PAGE_SHIFT) + min_low_pfn = memory_start >> PAGE_SHIFT; + + start_pfn = PAGE_OFFSET >> PAGE_SHIFT; + end_pfn = memory_end >> PAGE_SHIFT; /* * give all the memory to the bootmap allocator, tell it to put the @@ -580,7 +620,7 @@ static __init void setup_bootmem_allocator(void) */ bootmap_size = init_bootmem_node(NODE_DATA(0), memory_start >> PAGE_SHIFT, /* map goes here */ - min_pfn, max_pfn); + start_pfn, end_pfn); /* register the memmap regions with the bootmem allocator */ for (i = 0; i < bfin_memmap.nr_map; i++) { @@ -593,7 +633,7 @@ static __init void setup_bootmem_allocator(void) * We are rounding up the start address of usable memory: */ curr_pfn = PFN_UP(bfin_memmap.map[i].addr); - if (curr_pfn >= max_pfn) + if (curr_pfn >= end_pfn) continue; /* * ... and at the end of the usable range downwards: @@ -601,8 +641,8 @@ static __init void setup_bootmem_allocator(void) last_pfn = PFN_DOWN(bfin_memmap.map[i].addr + bfin_memmap.map[i].size); - if (last_pfn > max_pfn) - last_pfn = max_pfn; + if (last_pfn > end_pfn) + last_pfn = end_pfn; /* * .. finally, did all the rounding and playing @@ -621,12 +661,57 @@ static __init void setup_bootmem_allocator(void) BOOTMEM_DEFAULT); } -void __init setup_arch(char **cmdline_p) +#define EBSZ_TO_MEG(ebsz) \ +({ \ + int meg = 0; \ + switch (ebsz & 0xf) { \ + case 0x1: meg = 16; break; \ + case 0x3: meg = 32; break; \ + case 0x5: meg = 64; break; \ + case 0x7: meg = 128; break; \ + case 0x9: meg = 256; break; \ + case 0xb: meg = 512; break; \ + } \ + meg; \ +}) +static inline int __init get_mem_size(void) { - unsigned long l1_length, sclk, cclk; -#ifdef CONFIG_MTD_UCLINUX - unsigned long mtd_phys = 0; +#if defined(EBIU_SDBCTL) +# if defined(BF561_FAMILY) + int ret = 0; + u32 sdbctl = bfin_read_EBIU_SDBCTL(); + ret += EBSZ_TO_MEG(sdbctl >> 0); + ret += EBSZ_TO_MEG(sdbctl >> 8); + ret += EBSZ_TO_MEG(sdbctl >> 16); + ret += EBSZ_TO_MEG(sdbctl >> 24); + return ret; +# else + return EBSZ_TO_MEG(bfin_read_EBIU_SDBCTL()); +# endif +#elif defined(EBIU_DDRCTL1) + u32 ddrctl = bfin_read_EBIU_DDRCTL1(); + int ret = 0; + switch (ddrctl & 0xc0000) { + case DEVSZ_64: ret = 64 / 8; + case DEVSZ_128: ret = 128 / 8; + case DEVSZ_256: ret = 256 / 8; + case DEVSZ_512: ret = 512 / 8; + } + switch (ddrctl & 0x30000) { + case DEVWD_4: ret *= 2; + case DEVWD_8: ret *= 2; + case DEVWD_16: break; + } + if ((ddrctl & 0xc000) == 0x4000) + ret *= 2; + return ret; #endif + BUG(); +} + +void __init setup_arch(char **cmdline_p) +{ + unsigned long sclk, cclk; #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; @@ -644,7 +729,7 @@ void __init setup_arch(char **cmdline_p) /* setup memory defaults from the user config */ physical_mem_end = 0; - _ramend = CONFIG_MEM_SIZE * 1024 * 1024; + _ramend = get_mem_size() * 1024 * 1024; memset(&bfin_memmap, 0, sizeof(bfin_memmap)); @@ -655,6 +740,16 @@ void __init setup_arch(char **cmdline_p) memory_setup(); + /* Initialize Async memory banks */ + bfin_write_EBIU_AMBCTL0(AMBCTL0VAL); + bfin_write_EBIU_AMBCTL1(AMBCTL1VAL); + bfin_write_EBIU_AMGCTL(AMGCTLVAL); +#ifdef CONFIG_EBIU_MBSCTLVAL + bfin_write_EBIU_MBSCTL(CONFIG_EBIU_MBSCTLVAL); + bfin_write_EBIU_MODE(CONFIG_EBIU_MODEVAL); + bfin_write_EBIU_FCTL(CONFIG_EBIU_FCTLVAL); +#endif + cclk = get_cclk(); sclk = get_sclk(); @@ -688,14 +783,30 @@ void __init setup_arch(char **cmdline_p) _bfin_swrst = bfin_read_SWRST(); - if (_bfin_swrst & RESET_DOUBLE) - printk(KERN_INFO "Recovering from Double Fault event\n"); - else if (_bfin_swrst & RESET_WDOG) +#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT + bfin_write_SWRST(_bfin_swrst & ~DOUBLE_FAULT); +#endif +#ifdef CONFIG_DEBUG_DOUBLEFAULT_RESET + bfin_write_SWRST(_bfin_swrst | DOUBLE_FAULT); +#endif + + if (_bfin_swrst & RESET_DOUBLE) { + printk(KERN_EMERG "Recovering from DOUBLE FAULT event\n"); +#ifdef CONFIG_DEBUG_DOUBLEFAULT + /* We assume the crashing kernel, and the current symbol table match */ + printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n", + (int)init_saved_seqstat & SEQSTAT_EXCAUSE, init_saved_retx); + printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr); + printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr); +#endif + printk(KERN_NOTICE " The instruction at %pF caused a double exception\n", + init_retx); + } else if (_bfin_swrst & RESET_WDOG) printk(KERN_INFO "Recovering from Watchdog event\n"); else if (_bfin_swrst & RESET_SOFTWARE) printk(KERN_NOTICE "Reset caused by Software reset\n"); - printk(KERN_INFO "Blackfin support (C) 2004-2007 Analog Devices, Inc.\n"); + printk(KERN_INFO "Blackfin support (C) 2004-2008 Analog Devices, Inc.\n"); if (bfin_compiled_revid() == 0xffff) printk(KERN_INFO "Compiled for ADSP-%s Rev any\n", CPU); else if (bfin_compiled_revid() == -1) @@ -725,15 +836,6 @@ void __init setup_arch(char **cmdline_p) paging_init(); - /* check the size of the l1 area */ - l1_length = _etext_l1 - _stext_l1; - if (l1_length > L1_CODE_LENGTH) - panic("L1 code memory overflow\n"); - - l1_length = _ebss_l1 - _sdata_l1; - if (l1_length > L1_DATA_A_LENGTH) - panic("L1 data memory overflow\n"); - /* Copy atomic sequences to their fixed location, and sanity check that these locations are the ones that we advertise to userspace. */ memcpy((void *)FIXED_CODE_START, &fixed_code_start, @@ -758,56 +860,73 @@ void __init setup_arch(char **cmdline_p) != SAFE_USER_INSTRUCTION - FIXED_CODE_START); init_exception_vectors(); - bf53x_cache_init(); + bfin_cache_init(); } static int __init topology_init(void) { -#if defined (CONFIG_BF561) - static struct cpu cpu[2]; - register_cpu(&cpu[0], 0); - register_cpu(&cpu[1], 1); + int cpu; + + for_each_possible_cpu(cpu) { + struct cpu *c = &per_cpu(cpu_devices, cpu); + + register_cpu(c, cpu); + } + return 0; -#else - static struct cpu cpu[1]; - return register_cpu(cpu, 0); -#endif } subsys_initcall(topology_init); +/* Get the voltage input multiplier */ +static u_long cached_vco_pll_ctl, cached_vco; static u_long get_vco(void) { u_long msel; - u_long vco; - msel = (bfin_read_PLL_CTL() >> 9) & 0x3F; + u_long pll_ctl = bfin_read_PLL_CTL(); + if (pll_ctl == cached_vco_pll_ctl) + return cached_vco; + else + cached_vco_pll_ctl = pll_ctl; + + msel = (pll_ctl >> 9) & 0x3F; if (0 == msel) msel = 64; - vco = CONFIG_CLKIN_HZ; - vco >>= (1 & bfin_read_PLL_CTL()); /* DF bit */ - vco = msel * vco; - return vco; + cached_vco = CONFIG_CLKIN_HZ; + cached_vco >>= (1 & pll_ctl); /* DF bit */ + cached_vco *= msel; + return cached_vco; } /* Get the Core clock */ +static u_long cached_cclk_pll_div, cached_cclk; u_long get_cclk(void) { u_long csel, ssel; + if (bfin_read_PLL_STAT() & 0x1) return CONFIG_CLKIN_HZ; ssel = bfin_read_PLL_DIV(); + if (ssel == cached_cclk_pll_div) + return cached_cclk; + else + cached_cclk_pll_div = ssel; + csel = ((ssel >> 4) & 0x03); ssel &= 0xf; if (ssel && ssel < (1 << csel)) /* SCLK > CCLK */ - return get_vco() / ssel; - return get_vco() >> csel; + cached_cclk = get_vco() / ssel; + else + cached_cclk = get_vco() >> csel; + return cached_cclk; } EXPORT_SYMBOL(get_cclk); /* Get the System clock */ +static u_long cached_sclk_pll_div, cached_sclk; u_long get_sclk(void) { u_long ssel; @@ -815,13 +934,20 @@ u_long get_sclk(void) if (bfin_read_PLL_STAT() & 0x1) return CONFIG_CLKIN_HZ; - ssel = (bfin_read_PLL_DIV() & 0xf); + ssel = bfin_read_PLL_DIV(); + if (ssel == cached_sclk_pll_div) + return cached_sclk; + else + cached_sclk_pll_div = ssel; + + ssel &= 0xf; if (0 == ssel) { printk(KERN_WARNING "Invalid System Clock\n"); ssel = 1; } - return get_vco() / ssel; + cached_sclk = get_vco() / ssel; + return cached_sclk; } EXPORT_SYMBOL(get_sclk); @@ -850,7 +976,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) uint32_t revid; u_long cclk = 0, sclk = 0; - u_int dcache_size = 0, dsup_banks = 0; + u_int icache_size = BFIN_ICACHESIZE / 1024, dcache_size = 0, dsup_banks = 0; cpu = CPU; mmu = "none"; @@ -872,12 +998,17 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "processor\t: %d\n" "vendor_id\t: %s\n" "cpu family\t: 0x%x\n" - "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK)\n" + "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n" "stepping\t: %d\n", 0, vendor, (bfin_read_CHIPID() & CHIPID_FAMILY), cpu, cclk/1000000, sclk/1000000, +#ifdef CONFIG_MPU + "mpu on", +#else + "mpu off", +#endif revid); seq_printf(m, "cpu MHz\t\t: %lu.%03lu/%lu.%03lu\n", @@ -914,12 +1045,15 @@ static int show_cpuinfo(struct seq_file *m, void *v) } /* Is it turned on? */ - if (!((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE))) + if ((bfin_read_DMEM_CONTROL() & (ENDCPLB | DMC_ENABLE)) != (ENDCPLB | DMC_ENABLE)) dcache_size = 0; + if ((bfin_read_IMEM_CONTROL() & (IMC | ENICPLB)) == (IMC | ENICPLB)) + icache_size = 0; + seq_printf(m, "cache size\t: %d KB(L1 icache) " "%d KB(L1 dcache-%s) %d KB(L2 cache)\n", - BFIN_ICACHESIZE / 1024, dcache_size, + icache_size, dcache_size, #if defined CONFIG_BFIN_WB "wb" #elif defined CONFIG_BFIN_WT @@ -929,14 +1063,18 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "%s\n", cache); - seq_printf(m, "icache setup\t: %d Sub-banks/%d Ways, %d Lines/Way\n", - BFIN_ISUBBANKS, BFIN_IWAYS, BFIN_ILINES); + if (icache_size) + seq_printf(m, "icache setup\t: %d Sub-banks/%d Ways, %d Lines/Way\n", + BFIN_ISUBBANKS, BFIN_IWAYS, BFIN_ILINES); + else + seq_printf(m, "icache setup\t: off\n"); + seq_printf(m, "dcache setup\t: %d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n", dsup_banks, BFIN_DSUBBANKS, BFIN_DWAYS, BFIN_DLINES); #ifdef CONFIG_BFIN_ICACHE_LOCK - switch (read_iloc()) { + switch ((bfin_read_IMEM_CONTROL() >> 3) & WAYALL_L) { case WAY0_L: seq_printf(m, "Way0 Locked-Down\n"); break; @@ -986,7 +1124,6 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "No Ways are locked\n"); } #endif - seq_printf(m, "board name\t: %s\n", bfin_board_name); seq_printf(m, "board memory\t: %ld kB (0x%p -> 0x%p)\n", physical_mem_end >> 10, (void *)0, (void *)physical_mem_end);