#include <linux/bootmem.h>
#include <linux/seq_file.h>
#include <linux/cpu.h>
+#include <linux/mm.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/pfn.h>
+#ifdef CONFIG_MTD_UCLINUX
+#include <linux/mtd/map.h>
#include <linux/ext2_fs.h>
#include <linux/cramfs_fs.h>
#include <linux/romfs_fs.h>
+#endif
#include <asm/cplb.h>
#include <asm/cacheflush.h>
#include <asm/blackfin.h>
#include <asm/cplbinit.h>
#include <asm/div64.h>
+#include <asm/cpu.h>
#include <asm/fixed_code.h>
#include <asm/early_printk.h>
-static DEFINE_PER_CPU(struct cpu, cpu_devices);
-
u16 _bfin_swrst;
EXPORT_SYMBOL(_bfin_swrst);
EXPORT_SYMBOL(memory_end);
EXPORT_SYMBOL(physical_mem_end);
EXPORT_SYMBOL(_ramend);
+EXPORT_SYMBOL(reserved_mem_dcache_on);
#ifdef CONFIG_MTD_UCLINUX
+extern struct map_info uclinux_ram_map;
unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
unsigned long _ebss;
EXPORT_SYMBOL(memory_mtd_end);
#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 */
#define BFIN_MEMMAP_RAM 1
#define BFIN_MEMMAP_RESERVED 2
-struct bfin_memmap {
+static struct bfin_memmap {
int nr_map;
struct bfin_memmap_entry {
unsigned long long addr; /* start of memory segment */
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)
-{
+DEFINE_PER_CPU(struct blackfin_cpudata, cpu_data);
+
+static int early_init_clkin_hz(char *buf);
+
#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE)
- generate_cpl_tables();
+void __init generate_cplb_tables(void)
+{
+ unsigned int cpu;
+
+ generate_cplb_tables_all();
+ /* Generate per-CPU I&D CPLB tables */
+ for (cpu = 0; cpu < num_possible_cpus(); ++cpu)
+ generate_cplb_tables_cpu(cpu);
+}
#endif
+void __cpuinit bfin_setup_caches(unsigned int cpu)
+{
#ifdef CONFIG_BFIN_ICACHE
- bfin_icache_init();
- printk(KERN_INFO "Instruction Cache Enabled\n");
+ bfin_icache_init(icplb_tbl[cpu]);
+#endif
+
+#ifdef CONFIG_BFIN_DCACHE
+ bfin_dcache_init(dcplb_tbl[cpu]);
+#endif
+
+ /*
+ * In cache coherence emulation mode, we need to have the
+ * D-cache enabled before running any atomic operation which
+ * might invove cache invalidation (i.e. spinlock, rwlock).
+ * So printk's are deferred until then.
+ */
+#ifdef CONFIG_BFIN_ICACHE
+ printk(KERN_INFO "Instruction Cache Enabled for CPU%u\n", cpu);
+ printk(KERN_INFO " External memory:"
+# ifdef CONFIG_BFIN_EXTMEM_ICACHEABLE
+ " cacheable"
+# else
+ " uncacheable"
+# endif
+ " in instruction cache\n");
+ if (L2_LENGTH)
+ printk(KERN_INFO " L2 SRAM :"
+# ifdef CONFIG_BFIN_L2_ICACHEABLE
+ " cacheable"
+# else
+ " uncacheable"
+# endif
+ " in instruction cache\n");
+
+#else
+ printk(KERN_INFO "Instruction Cache Disabled for CPU%u\n", cpu);
#endif
#ifdef CONFIG_BFIN_DCACHE
- bfin_dcache_init();
- printk(KERN_INFO "Data Cache Enabled"
-# if defined CONFIG_BFIN_WB
- " (write-back)"
-# elif defined CONFIG_BFIN_WT
- " (write-through)"
+ printk(KERN_INFO "Data Cache Enabled for CPU%u\n", cpu);
+ printk(KERN_INFO " External memory:"
+# if defined CONFIG_BFIN_EXTMEM_WRITEBACK
+ " cacheable (write-back)"
+# elif defined CONFIG_BFIN_EXTMEM_WRITETHROUGH
+ " cacheable (write-through)"
+# else
+ " uncacheable"
+# endif
+ " in data cache\n");
+ if (L2_LENGTH)
+ printk(KERN_INFO " L2 SRAM :"
+# if defined CONFIG_BFIN_L2_WRITEBACK
+ " cacheable (write-back)"
+# elif defined CONFIG_BFIN_L2_WRITETHROUGH
+ " cacheable (write-through)"
+# else
+ " uncacheable"
# endif
- "\n");
+ " in data cache\n");
+#else
+ printk(KERN_INFO "Data Cache Disabled for CPU%u\n", cpu);
#endif
}
-void __init bf53x_relocate_l1_mem(void)
+void __cpuinit bfin_setup_cpudata(unsigned int cpu)
+{
+ struct blackfin_cpudata *cpudata = &per_cpu(cpu_data, cpu);
+
+ cpudata->idle = current;
+ cpudata->imemctl = bfin_read_IMEM_CONTROL();
+ cpudata->dmemctl = bfin_read_DMEM_CONTROL();
+}
+
+void __init bfin_cache_init(void)
+{
+#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE)
+ generate_cplb_tables();
+#endif
+ bfin_setup_caches(0);
+}
+
+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)
- panic("L1 Instruction SRAM Overflow\n");
- /* cannot complain as printk is not available as yet.
- * But we can continue booting and complain later!
- */
-
- /* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
- dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
+ early_shadow_stamp();
- l1_data_a_length = _ebss_l1 - _sdata_l1;
- if (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);
+ /*
+ * due to the ALIGN(4) in the arch/blackfin/kernel/vmlinux.lds.S
+ * we know that everything about l1 text/data is nice and aligned,
+ * so copy by 4 byte chunks, and don't worry about overlapping
+ * src/dest.
+ *
+ * We can't use the dma_memcpy functions, since they can call
+ * scheduler functions which might be in L1 :( and core writes
+ * into L1 instruction cause bad access errors, so we are stuck,
+ * we are required to use DMA, but can't use the common dma
+ * functions. We can't use memcpy either - since that might be
+ * going to be in the relocated L1
+ */
- l1_data_b_length = _ebss_b_l1 - _sdata_b_l1;
- if (l1_data_b_length > L1_DATA_B_LENGTH)
- panic("L1 Data SRAM Bank B Overflow\n");
+ blackfin_dma_early_init();
- /* 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 +
+ /* if necessary, copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
+ l1_code_length = _etext_l1 - _stext_l1;
+ if (l1_code_length)
+ early_dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
+
+ /* if necessary, copy _sdata_l1 to _sbss_l1 to L1 data bank A SRAM */
+ l1_data_a_length = _sbss_l1 - _sdata_l1;
+ if (l1_data_a_length)
+ early_dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
+
+ /* if necessary, copy _sdata_b_l1 to _sbss_b_l1 to L1 data bank B SRAM */
+ l1_data_b_length = _sbss_b_l1 - _sdata_b_l1;
+ if (l1_data_b_length)
+ early_dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
l1_data_a_length, l1_data_b_length);
-#ifdef L2_LENGTH
- l2_length = _ebss_l2 - _stext_l2;
- if (l2_length > L2_LENGTH)
- panic("L2 SRAM Overflow\n");
+ early_dma_memcpy_done();
- /* Copy _stext_l2 to _edata_l2 to L2 SRAM */
- dma_memcpy(_stext_l2, _l2_lma_start, l2_length);
-#endif
+ /* if necessary, copy _stext_l2 to _edata_l2 to L2 SRAM */
+ if (L2_LENGTH != 0) {
+ l2_length = _sbss_l2 - _stext_l2;
+ if (l2_length)
+ memcpy(_stext_l2, _l2_lma_start, l2_length);
+ }
}
/* add_memory_region to memmap */
/* record all known change-points (starting and ending addresses),
omitting those that are for empty memory regions */
chgidx = 0;
- for (i = 0; i < old_nr; i++) {
+ for (i = 0; i < old_nr; i++) {
if (map[i].size != 0) {
change_point[chgidx]->addr = map[i].addr;
change_point[chgidx++]->pentry = &map[i];
change_point[chgidx++]->pentry = &map[i];
}
}
- chg_nr = chgidx; /* true number of change-points */
+ chg_nr = chgidx; /* true number of change-points */
/* sort change-point list by memory addresses (low -> high) */
still_changing = 1;
- while (still_changing) {
+ while (still_changing) {
still_changing = 0;
- for (i = 1; i < chg_nr; i++) {
+ for (i = 1; i < chg_nr; i++) {
/* if <current_addr> > <last_addr>, swap */
/* or, if current=<start_addr> & last=<end_addr>, swap */
if ((change_point[i]->addr < change_point[i-1]->addr) ||
}
/* create a new memmap, removing overlaps */
- overlap_entries = 0; /* number of entries in the overlap table */
- new_entry = 0; /* index for creating new memmap entries */
- last_type = 0; /* start with undefined memory type */
- last_addr = 0; /* start with 0 as last starting address */
+ overlap_entries = 0; /* number of entries in the overlap table */
+ new_entry = 0; /* index for creating new memmap entries */
+ last_type = 0; /* start with undefined memory type */
+ last_addr = 0; /* start with 0 as last starting address */
/* loop through change-points, determining affect on the new memmap */
for (chgidx = 0; chgidx < chg_nr; chgidx++) {
/* keep track of all overlapping memmap entries */
if (overlap_list[i]->type > current_type)
current_type = overlap_list[i]->type;
/* continue building up new memmap based on this information */
- if (current_type != last_type) {
+ if (current_type != last_type) {
if (last_type != 0) {
new_map[new_entry].size =
change_point[chgidx]->addr - last_addr;
/* move forward only if the new size was non-zero */
if (new_map[new_entry].size != 0)
if (++new_entry >= BFIN_MEMMAP_MAX)
- break; /* no more space left for new entries */
+ break; /* no more space left for new entries */
}
if (current_type != 0) {
new_map[new_entry].addr = change_point[chgidx]->addr;
last_type = current_type;
}
}
- new_nr = new_entry; /* retain count for new entries */
+ new_nr = new_entry; /* retain count for new entries */
- /* copy new mapping into original location */
+ /* copy new mapping into original location */
memcpy(map, new_map, new_nr*sizeof(struct bfin_memmap_entry));
*pnr_map = new_nr;
bfin_memmap.map[i].addr + bfin_memmap.map[i].size);
switch (bfin_memmap.map[i].type) {
case BFIN_MEMMAP_RAM:
- printk("(usable)\n");
- break;
+ printk(KERN_CONT "(usable)\n");
+ break;
case BFIN_MEMMAP_RESERVED:
- printk("(reserved)\n");
- break;
- default: printk("type %lu\n", bfin_memmap.map[i].type);
- break;
+ printk(KERN_CONT "(reserved)\n");
+ break;
+ default:
+ printk(KERN_CONT "type %lu\n", bfin_memmap.map[i].type);
+ break;
}
}
}
* - "memmap=XXX[KkmM][@][$]XXX[KkmM]" defines a memory region
* @ from <start> to <start>+<mem>, type RAM
* $ from <start> to <start>+<mem>, type RESERVED
- *
*/
static __init void parse_cmdline_early(char *cmdline_p)
{
if (*to != ' ') {
if (*to == '$'
|| *(to + 1) == '$')
- reserved_mem_dcache_on =
- 1;
+ reserved_mem_dcache_on = 1;
if (*to == '#'
|| *(to + 1) == '#')
- reserved_mem_icache_on =
- 1;
+ reserved_mem_icache_on = 1;
}
}
+ } else if (!memcmp(to, "clkin_hz=", 9)) {
+ to += 9;
+ early_init_clkin_hz(to);
+#ifdef CONFIG_EARLY_PRINTK
} else if (!memcmp(to, "earlyprintk=", 12)) {
to += 12;
setup_early_printk(to);
+#endif
} else if (!memcmp(to, "memmap=", 7)) {
to += 7;
parse_memmap(to);
* [_rambase, _ramstart]: kernel image
* [memory_start, memory_end]: dynamic memory managed by kernel
* [memory_end, _ramend]: reserved memory
- * [meory_mtd_start(memory_end),
+ * [memory_mtd_start(memory_end),
* memory_mtd_start + mtd_size]: rootfs (if any)
* [_ramend - DMA_UNCACHED_REGION,
* _ramend]: uncached DMA region
* [_ramend, physical_mem_end]: memory not managed by kernel
- *
*/
-static __init void memory_setup(void)
+static __init void memory_setup(void)
{
#ifdef CONFIG_MTD_UCLINUX
unsigned long mtd_phys = 0;
#endif
+ unsigned long max_mem;
_rambase = (unsigned long)_stext;
_ramstart = (unsigned long)_end;
if (DMA_UNCACHED_REGION > (_ramend - _ramstart)) {
console_init();
- panic("DMA region exceeds memory limit: %lu.\n",
+ panic("DMA region exceeds memory limit: %lu.",
_ramend - _ramstart);
}
- memory_end = _ramend - DMA_UNCACHED_REGION;
+ max_mem = memory_end = _ramend - DMA_UNCACHED_REGION;
+
+#if (defined(CONFIG_BFIN_EXTMEM_ICACHEABLE) && ANOMALY_05000263)
+ /* Due to a Hardware Anomaly we need to limit the size of usable
+ * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
+ * 05000263 - Hardware loop corrupted when taking an ICPLB exception
+ */
+# if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
+ if (max_mem >= 56 * 1024 * 1024)
+ max_mem = 56 * 1024 * 1024;
+# else
+ if (max_mem >= 60 * 1024 * 1024)
+ max_mem = 60 * 1024 * 1024;
+# endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
+#endif /* ANOMALY_05000263 */
+
#ifdef CONFIG_MPU
- /* Round up to multiple of 4MB. */
+ /* Round up to multiple of 4MB */
memory_start = (_ramstart + 0x3fffff) & ~0x3fffff;
#else
memory_start = PAGE_ALIGN(_ramstart);
# if defined(CONFIG_ROMFS_FS)
if (((unsigned long *)mtd_phys)[0] == ROMSB_WORD0
- && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1)
+ && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1) {
mtd_size =
PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2]));
-# if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263)
- /* Due to a Hardware Anomaly we need to limit the size of usable
- * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
- * 05000263 - Hardware loop corrupted when taking an ICPLB exception
- */
-# if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
- if (memory_end >= 56 * 1024 * 1024)
- memory_end = 56 * 1024 * 1024;
-# else
- if (memory_end >= 60 * 1024 * 1024)
- memory_end = 60 * 1024 * 1024;
-# endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
-# endif /* ANOMALY_05000263 */
-# endif /* CONFIG_ROMFS_FS */
-
- memory_end -= mtd_size;
- if (mtd_size == 0) {
- console_init();
- panic("Don't boot kernel without rootfs attached.\n");
+ /* ROM_FS is XIP, so if we found it, we need to limit memory */
+ if (memory_end > max_mem) {
+ pr_info("Limiting kernel memory to %liMB due to anomaly 05000263\n", max_mem >> 20);
+ memory_end = max_mem;
+ }
}
+# endif /* CONFIG_ROMFS_FS */
- /* Relocate MTD image to the top of memory after the uncached memory area */
- dma_memcpy((char *)memory_end, _end, mtd_size);
-
- memory_mtd_start = memory_end;
- _ebss = memory_mtd_start; /* define _ebss for compatible */
+ /* Since the default MTD_UCLINUX has no magic number, we just blindly
+ * read 8 past the end of the kernel's image, and look at it.
+ * When no image is attached, mtd_size is set to a random number
+ * Do some basic sanity checks before operating on things
+ */
+ if (mtd_size == 0 || memory_end <= mtd_size) {
+ pr_emerg("Could not find valid ram mtd attached.\n");
+ } else {
+ memory_end -= mtd_size;
+
+ /* Relocate MTD image to the top of memory after the uncached memory area */
+ uclinux_ram_map.phys = memory_mtd_start = memory_end;
+ uclinux_ram_map.size = mtd_size;
+ pr_info("Found mtd parition at 0x%p, (len=0x%lx), moving to 0x%p\n",
+ _end, mtd_size, (void *)memory_mtd_start);
+ dma_memcpy((void *)uclinux_ram_map.phys, _end, uclinux_ram_map.size);
+ }
#endif /* CONFIG_MTD_UCLINUX */
-#if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263)
- /* Due to a Hardware Anomaly we need to limit the size of usable
- * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
- * 05000263 - Hardware loop corrupted when taking an ICPLB exception
+ /* We need lo limit memory, since everything could have a text section
+ * of userspace in it, and expose anomaly 05000263. If the anomaly
+ * doesn't exist, or we don't need to - then dont.
*/
-#if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
- if (memory_end >= 56 * 1024 * 1024)
- memory_end = 56 * 1024 * 1024;
-#else
- if (memory_end >= 60 * 1024 * 1024)
- memory_end = 60 * 1024 * 1024;
-#endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
- printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
-#endif /* ANOMALY_05000263 */
+ if (memory_end > max_mem) {
+ pr_info("Limiting kernel memory to %liMB due to anomaly 05000263\n", max_mem >> 20);
+ memory_end = max_mem;
+ }
#ifdef CONFIG_MPU
page_mask_nelts = ((_ramend >> PAGE_SHIFT) + 31) / 32;
printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20);
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 " available = 0x%p-0x%p\n"
+ " fixedcode = 0x%p-0x%p\n"
+ " text = 0x%p-0x%p\n"
+ " rodata = 0x%p-0x%p\n"
+ " bss = 0x%p-0x%p\n"
+ " data = 0x%p-0x%p\n"
+ " stack = 0x%p-0x%p\n"
+ " init = 0x%p-0x%p\n"
+ " available = 0x%p-0x%p\n"
#ifdef CONFIG_MTD_UCLINUX
- KERN_INFO " rootfs = 0x%p-0x%p\n"
+ " rootfs = 0x%p-0x%p\n"
#endif
#if DMA_UNCACHED_REGION > 0
- KERN_INFO " DMA Zone = 0x%p-0x%p\n"
+ " DMA Zone = 0x%p-0x%p\n"
#endif
, (void *)FIXED_CODE_START, (void *)FIXED_CODE_END,
_stext, _etext,
end_pfn = memory_end >> PAGE_SHIFT;
/*
- * give all the memory to the bootmap allocator, tell it to put the
+ * give all the memory to the bootmap allocator, tell it to put the
* boot mem_map at the start of memory.
*/
bootmap_size = init_bootmem_node(NODE_DATA(0),
{
unsigned long sclk, cclk;
+ enable_shadow_console();
+
+ /* Check to make sure we are running on the right processor */
+ if (unlikely(CPUID != bfin_cpuid()))
+ printk(KERN_ERR "ERROR: Not running on ADSP-%s: unknown CPUID 0x%04x Rev 0.%d\n",
+ CPU, bfin_cpuid(), bfin_revid());
+
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
boot_command_line[COMMAND_LINE_SIZE - 1] = '\0';
- /* setup memory defaults from the user config */
- physical_mem_end = 0;
- _ramend = get_mem_size() * 1024 * 1024;
-
memset(&bfin_memmap, 0, sizeof(bfin_memmap));
+ /* If the user does not specify things on the command line, use
+ * what the bootloader set things up as
+ */
+ physical_mem_end = 0;
parse_cmdline_early(&command_line[0]);
+ if (_ramend == 0)
+ _ramend = get_mem_size() * 1024 * 1024;
+
if (physical_mem_end == 0)
physical_mem_end = _ramend;
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();
-#if !defined(CONFIG_BFIN_KERNEL_CLOCK)
- if (ANOMALY_05000273 && cclk == sclk)
- panic("ANOMALY 05000273, SCLK can not be same as CCLK");
-#endif
+ if ((ANOMALY_05000273 || ANOMALY_05000274) && (cclk >> 1) < sclk)
+ panic("ANOMALY 05000273 or 05000274: CCLK must be >= 2*SCLK");
#ifdef BF561_FAMILY
if (ANOMALY_05000266) {
#endif
printk(KERN_INFO "Hardware Trace ");
if (bfin_read_TBUFCTL() & 0x1)
- printk("Active ");
+ printk(KERN_CONT "Active ");
else
- printk("Off ");
+ printk(KERN_CONT "Off ");
if (bfin_read_TBUFCTL() & 0x2)
- printk("and Enabled\n");
+ printk(KERN_CONT "and Enabled\n");
else
- printk("and Disabled\n");
+ printk(KERN_CONT "and Disabled\n");
-#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
- /* we need to initialize the Flashrom device here since we might
- * do things with flash early on in the boot
- */
- flash_probe();
-#endif
+ printk(KERN_INFO "Boot Mode: %i\n", bfin_read_SYSCR() & 0xF);
+ /* Newer parts mirror SWRST bits in SYSCR */
+#if defined(CONFIG_BF53x) || defined(CONFIG_BF561) || \
+ defined(CONFIG_BF538) || defined(CONFIG_BF539)
_bfin_swrst = bfin_read_SWRST();
+#else
+ /* Clear boot mode field */
+ _bfin_swrst = bfin_read_SYSCR() & ~0xf;
+#endif
- 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
+
+#ifdef CONFIG_SMP
+ if (_bfin_swrst & SWRST_DBL_FAULT_A) {
+#else
+ if (_bfin_swrst & RESET_DOUBLE) {
+#endif
+ 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-2008 Analog Devices, Inc.\n");
+ printk(KERN_INFO "Blackfin support (C) 2004-2009 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)
printk(KERN_INFO "Compiled for ADSP-%s Rev none\n", CPU);
else
printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid());
- if (bfin_revid() != bfin_compiled_revid()) {
- if (bfin_compiled_revid() == -1)
- printk(KERN_ERR "Warning: Compiled for Rev none, but running on Rev %d\n",
- bfin_revid());
- else if (bfin_compiled_revid() != 0xffff)
- printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
- bfin_compiled_revid(), bfin_revid());
+
+ if (likely(CPUID == bfin_cpuid())) {
+ if (bfin_revid() != bfin_compiled_revid()) {
+ if (bfin_compiled_revid() == -1)
+ printk(KERN_ERR "Warning: Compiled for Rev none, but running on Rev %d\n",
+ bfin_revid());
+ else if (bfin_compiled_revid() != 0xffff) {
+ printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
+ bfin_compiled_revid(), bfin_revid());
+ if (bfin_compiled_revid() > bfin_revid())
+ panic("Error: you are missing anomaly workarounds for this rev");
+ }
+ }
+ if (bfin_revid() < CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX)
+ printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
+ CPU, bfin_revid());
}
- if (bfin_revid() < SUPPORTED_REVID)
- printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
- CPU, bfin_revid());
+
printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu MHz System Clock\n",
- cclk / 1000000, sclk / 1000000);
-
- if (ANOMALY_05000273 && (cclk >> 1) <= sclk)
- printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n");
+ cclk / 1000000, sclk / 1000000);
setup_bootmem_allocator();
BUG_ON((char *)&safe_user_instruction - (char *)&fixed_code_start
!= SAFE_USER_INSTRUCTION - FIXED_CODE_START);
+#ifdef CONFIG_SMP
+ platform_init_cpus();
+#endif
init_exception_vectors();
- bf53x_cache_init();
+ bfin_cache_init(); /* Initialize caches for the boot CPU */
}
static int __init topology_init(void)
{
- int cpu;
+ unsigned int cpu;
+ /* Record CPU-private information for the boot processor. */
+ bfin_setup_cpudata(0);
for_each_possible_cpu(cpu) {
- struct cpu *c = &per_cpu(cpu_devices, cpu);
-
- register_cpu(c, cpu);
+ register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu);
}
return 0;
subsys_initcall(topology_init);
+/* Get the input clock frequency */
+static u_long cached_clkin_hz = CONFIG_CLKIN_HZ;
+static u_long get_clkin_hz(void)
+{
+ return cached_clkin_hz;
+}
+static int __init early_init_clkin_hz(char *buf)
+{
+ cached_clkin_hz = simple_strtoul(buf, NULL, 0);
+#ifdef BFIN_KERNEL_CLOCK
+ if (cached_clkin_hz != CONFIG_CLKIN_HZ)
+ panic("cannot change clkin_hz when reprogramming clocks");
+#endif
+ return 1;
+}
+early_param("clkin_hz=", early_init_clkin_hz);
+
+/* Get the voltage input multiplier */
static u_long get_vco(void)
{
- u_long msel;
- u_long vco;
+ static u_long cached_vco;
+ u_long msel, pll_ctl;
+
+ /* The assumption here is that VCO never changes at runtime.
+ * If, someday, we support that, then we'll have to change this.
+ */
+ if (cached_vco)
+ return cached_vco;
- msel = (bfin_read_PLL_CTL() >> 9) & 0x3F;
+ pll_ctl = bfin_read_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 = get_clkin_hz();
+ cached_vco >>= (1 & pll_ctl); /* DF bit */
+ cached_vco *= msel;
+ return cached_vco;
}
/* Get the Core clock */
u_long get_cclk(void)
{
+ static u_long cached_cclk_pll_div, cached_cclk;
u_long csel, ssel;
+
if (bfin_read_PLL_STAT() & 0x1)
- return CONFIG_CLKIN_HZ;
+ return get_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 */
u_long get_sclk(void)
{
+ static u_long cached_sclk;
u_long ssel;
+ /* The assumption here is that SCLK never changes at runtime.
+ * If, someday, we support that, then we'll have to change this.
+ */
+ if (cached_sclk)
+ return cached_sclk;
+
if (bfin_read_PLL_STAT() & 0x1)
- return CONFIG_CLKIN_HZ;
+ return get_clkin_hz();
- ssel = (bfin_read_PLL_DIV() & 0xf);
+ ssel = bfin_read_PLL_DIV() & 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);
{
char *cpu, *mmu, *fpu, *vendor, *cache;
uint32_t revid;
-
- u_long cclk = 0, sclk = 0;
- u_int dcache_size = 0, dsup_banks = 0;
+ int cpu_num = *(unsigned int *)v;
+ u_long sclk, cclk;
+ u_int icache_size = BFIN_ICACHESIZE / 1024, dcache_size = 0, dsup_banks = 0;
+ struct blackfin_cpudata *cpudata = &per_cpu(cpu_data, cpu_num);
cpu = CPU;
mmu = "none";
fpu = "none";
revid = bfin_revid();
- cclk = get_cclk();
sclk = get_sclk();
+ cclk = get_cclk();
switch (bfin_read_CHIPID() & CHIPID_MANUFACTURE) {
case 0xca:
break;
}
- 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) (%s)\n"
- "stepping\t: %d\n",
- 0,
- vendor,
- (bfin_read_CHIPID() & CHIPID_FAMILY),
+ seq_printf(m, "processor\t: %d\n" "vendor_id\t: %s\n", cpu_num, vendor);
+
+ if (CPUID == bfin_cpuid())
+ seq_printf(m, "cpu family\t: 0x%04x\n", CPUID);
+ else
+ seq_printf(m, "cpu family\t: Compiled for:0x%04x, running on:0x%04x\n",
+ CPUID, bfin_cpuid());
+
+ seq_printf(m, "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n"
+ "stepping\t: %d ",
cpu, cclk/1000000, sclk/1000000,
#ifdef CONFIG_MPU
"mpu on",
#endif
revid);
- seq_printf(m, "cpu MHz\t\t: %lu.%03lu/%lu.%03lu\n",
+ if (bfin_revid() != bfin_compiled_revid()) {
+ if (bfin_compiled_revid() == -1)
+ seq_printf(m, "(Compiled for Rev none)");
+ else if (bfin_compiled_revid() == 0xffff)
+ seq_printf(m, "(Compiled for Rev any)");
+ else
+ seq_printf(m, "(Compiled for Rev %d)", bfin_compiled_revid());
+ }
+
+ seq_printf(m, "\ncpu MHz\t\t: %lu.%03lu/%lu.%03lu\n",
cclk/1000000, cclk%1000000,
sclk/1000000, sclk%1000000);
seq_printf(m, "bogomips\t: %lu.%02lu\n"
(loops_per_jiffy * HZ));
/* Check Cache configutation */
- switch (bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) {
+ switch (cpudata->dmemctl & (1 << DMC0_P | 1 << DMC1_P)) {
case ACACHE_BSRAM:
cache = "dbank-A/B\t: cache/sram";
dcache_size = 16;
}
/* Is it turned on? */
- if (!((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE)))
+ if ((cpudata->dmemctl & (ENDCPLB | DMC_ENABLE)) != (ENDCPLB | DMC_ENABLE))
dcache_size = 0;
+ if ((cpudata->imemctl & (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,
-#if defined CONFIG_BFIN_WB
- "wb"
-#elif defined CONFIG_BFIN_WT
- "wt"
+ "%d KB(L1 dcache) %d KB(L2 cache)\n",
+ icache_size, dcache_size, 0);
+ seq_printf(m, "%s\n", cache);
+ seq_printf(m, "external memory\t: "
+#if defined(CONFIG_BFIN_EXTMEM_ICACHEABLE)
+ "cacheable"
+#else
+ "uncacheable"
#endif
- "", 0);
+ " in instruction cache\n");
+ seq_printf(m, "external memory\t: "
+#if defined(CONFIG_BFIN_EXTMEM_WRITEBACK)
+ "cacheable (write-back)"
+#elif defined(CONFIG_BFIN_EXTMEM_WRITETHROUGH)
+ "cacheable (write-through)"
+#else
+ "uncacheable"
+#endif
+ " in data cache\n");
- seq_printf(m, "%s\n", cache);
+ 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, "icache setup\t: %d Sub-banks/%d Ways, %d Lines/Way\n",
- BFIN_ISUBBANKS, BFIN_IWAYS, BFIN_ILINES);
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()) {
- case WAY0_L:
- seq_printf(m, "Way0 Locked-Down\n");
- break;
- case WAY1_L:
- seq_printf(m, "Way1 Locked-Down\n");
- break;
- case WAY01_L:
- seq_printf(m, "Way0,Way1 Locked-Down\n");
- break;
- case WAY2_L:
- seq_printf(m, "Way2 Locked-Down\n");
- break;
- case WAY02_L:
- seq_printf(m, "Way0,Way2 Locked-Down\n");
- break;
- case WAY12_L:
- seq_printf(m, "Way1,Way2 Locked-Down\n");
- break;
- case WAY012_L:
- seq_printf(m, "Way0,Way1 & Way2 Locked-Down\n");
- break;
- case WAY3_L:
- seq_printf(m, "Way3 Locked-Down\n");
- break;
- case WAY03_L:
- seq_printf(m, "Way0,Way3 Locked-Down\n");
- break;
- case WAY13_L:
- seq_printf(m, "Way1,Way3 Locked-Down\n");
- break;
- case WAY013_L:
- seq_printf(m, "Way 0,Way1,Way3 Locked-Down\n");
- break;
- case WAY32_L:
- seq_printf(m, "Way3,Way2 Locked-Down\n");
- break;
- case WAY320_L:
- seq_printf(m, "Way3,Way2,Way0 Locked-Down\n");
- break;
- case WAY321_L:
- seq_printf(m, "Way3,Way2,Way1 Locked-Down\n");
- break;
- case WAYALL_L:
- seq_printf(m, "All Ways are locked\n");
- break;
- default:
- seq_printf(m, "No Ways are locked\n");
- }
+#ifdef __ARCH_SYNC_CORE_DCACHE
+ seq_printf(m, "SMP Dcache Flushes\t: %lu\n\n", cpudata->dcache_invld_count);
#endif
+#ifdef __ARCH_SYNC_CORE_ICACHE
+ seq_printf(m, "SMP Icache Flushes\t: %lu\n\n", cpudata->icache_invld_count);
+#endif
+
+ if (cpu_num != num_possible_cpus() - 1)
+ return 0;
+
+ if (L2_LENGTH) {
+ seq_printf(m, "L2 SRAM\t\t: %dKB\n", L2_LENGTH/0x400);
+ seq_printf(m, "L2 SRAM\t\t: "
+#if defined(CONFIG_BFIN_L2_ICACHEABLE)
+ "cacheable"
+#else
+ "uncacheable"
+#endif
+ " in instruction cache\n");
+ seq_printf(m, "L2 SRAM\t\t: "
+#if defined(CONFIG_BFIN_L2_WRITEBACK)
+ "cacheable (write-back)"
+#elif defined(CONFIG_BFIN_L2_WRITETHROUGH)
+ "cacheable (write-through)"
+#else
+ "uncacheable"
+#endif
+ " in data cache\n");
+ }
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);
((int)memory_end - (int)_stext) >> 10,
_stext,
(void *)memory_end);
+ seq_printf(m, "\n");
return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
{
- return *pos < NR_CPUS ? ((void *)0x12345678) : NULL;
+ if (*pos == 0)
+ *pos = first_cpu(cpu_online_map);
+ if (*pos >= num_online_cpus())
+ return NULL;
+
+ return pos;
}
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
- ++*pos;
+ *pos = next_cpu(*pos, cpu_online_map);
+
return c_start(m, pos);
}
void __init cmdline_init(const char *r0)
{
+ early_shadow_stamp();
if (r0)
strncpy(command_line, r0, COMMAND_LINE_SIZE);
}