de4f6e5b41
The header files in the asm-xtensa directory are not clean and 'make headers_check' fails. This is a first patch to fix most of the header files. It removes unnecessary include statements and adds some that are required for building the kernel. The linker script required some updates or the linking stage would fail. Signed-off-by: Chris Zankel <chris@zankel.net>
481 lines
10 KiB
C
481 lines
10 KiB
C
/*
|
|
* arch/xtensa/kernel/setup.c
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*
|
|
* Copyright (C) 1995 Linus Torvalds
|
|
* Copyright (C) 2001 - 2005 Tensilica Inc.
|
|
*
|
|
* Chris Zankel <chris@zankel.net>
|
|
* Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
|
|
* Kevin Chea
|
|
* Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
|
|
*/
|
|
|
|
#include <linux/errno.h>
|
|
#include <linux/init.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/screen_info.h>
|
|
#include <linux/bootmem.h>
|
|
#include <linux/kernel.h>
|
|
|
|
#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
|
|
# include <linux/console.h>
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTC
|
|
# include <linux/timex.h>
|
|
#endif
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
# include <linux/seq_file.h>
|
|
#endif
|
|
|
|
#include <asm/system.h>
|
|
#include <asm/bootparam.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/timex.h>
|
|
#include <asm/platform.h>
|
|
#include <asm/page.h>
|
|
#include <asm/setup.h>
|
|
#include <asm/param.h>
|
|
|
|
#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
|
|
struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
|
|
#endif
|
|
|
|
#ifdef CONFIG_BLK_DEV_FD
|
|
extern struct fd_ops no_fd_ops;
|
|
struct fd_ops *fd_ops;
|
|
#endif
|
|
|
|
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
|
|
extern struct ide_ops no_ide_ops;
|
|
struct ide_ops *ide_ops;
|
|
#endif
|
|
|
|
extern struct rtc_ops no_rtc_ops;
|
|
struct rtc_ops *rtc_ops;
|
|
|
|
#ifdef CONFIG_PC_KEYB
|
|
extern struct kbd_ops no_kbd_ops;
|
|
struct kbd_ops *kbd_ops;
|
|
#endif
|
|
|
|
#ifdef CONFIG_BLK_DEV_INITRD
|
|
extern void *initrd_start;
|
|
extern void *initrd_end;
|
|
extern void *__initrd_start;
|
|
extern void *__initrd_end;
|
|
int initrd_is_mapped = 0;
|
|
extern int initrd_below_start_ok;
|
|
#endif
|
|
|
|
unsigned char aux_device_present;
|
|
extern unsigned long loops_per_jiffy;
|
|
|
|
/* Command line specified as configuration option. */
|
|
|
|
static char __initdata command_line[COMMAND_LINE_SIZE];
|
|
|
|
#ifdef CONFIG_CMDLINE_BOOL
|
|
static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
|
|
#endif
|
|
|
|
sysmem_info_t __initdata sysmem;
|
|
|
|
#ifdef CONFIG_BLK_DEV_INITRD
|
|
int initrd_is_mapped;
|
|
#endif
|
|
|
|
extern void init_mmu(void);
|
|
|
|
/*
|
|
* Boot parameter parsing.
|
|
*
|
|
* The Xtensa port uses a list of variable-sized tags to pass data to
|
|
* the kernel. The first tag must be a BP_TAG_FIRST tag for the list
|
|
* to be recognised. The list is terminated with a zero-sized
|
|
* BP_TAG_LAST tag.
|
|
*/
|
|
|
|
typedef struct tagtable {
|
|
u32 tag;
|
|
int (*parse)(const bp_tag_t*);
|
|
} tagtable_t;
|
|
|
|
#define __tagtable(tag, fn) static tagtable_t __tagtable_##fn \
|
|
__attribute__((unused, __section__(".taglist"))) = { tag, fn }
|
|
|
|
/* parse current tag */
|
|
|
|
static int __init parse_tag_mem(const bp_tag_t *tag)
|
|
{
|
|
meminfo_t *mi = (meminfo_t*)(tag->data);
|
|
|
|
if (mi->type != MEMORY_TYPE_CONVENTIONAL)
|
|
return -1;
|
|
|
|
if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
|
|
printk(KERN_WARNING
|
|
"Ignoring memory bank 0x%08lx size %ldKB\n",
|
|
(unsigned long)mi->start,
|
|
(unsigned long)mi->end - (unsigned long)mi->start);
|
|
return -EINVAL;
|
|
}
|
|
sysmem.bank[sysmem.nr_banks].type = mi->type;
|
|
sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start);
|
|
sysmem.bank[sysmem.nr_banks].end = mi->end & PAGE_SIZE;
|
|
sysmem.nr_banks++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__tagtable(BP_TAG_MEMORY, parse_tag_mem);
|
|
|
|
#ifdef CONFIG_BLK_DEV_INITRD
|
|
|
|
static int __init parse_tag_initrd(const bp_tag_t* tag)
|
|
{
|
|
meminfo_t* mi;
|
|
mi = (meminfo_t*)(tag->data);
|
|
initrd_start = (void*)(mi->start);
|
|
initrd_end = (void*)(mi->end);
|
|
|
|
return 0;
|
|
}
|
|
|
|
__tagtable(BP_TAG_INITRD, parse_tag_initrd);
|
|
|
|
#endif /* CONFIG_BLK_DEV_INITRD */
|
|
|
|
static int __init parse_tag_cmdline(const bp_tag_t* tag)
|
|
{
|
|
strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE);
|
|
command_line[COMMAND_LINE_SIZE - 1] = '\0';
|
|
return 0;
|
|
}
|
|
|
|
__tagtable(BP_TAG_COMMAND_LINE, parse_tag_cmdline);
|
|
|
|
static int __init parse_bootparam(const bp_tag_t* tag)
|
|
{
|
|
extern tagtable_t __tagtable_begin, __tagtable_end;
|
|
tagtable_t *t;
|
|
|
|
/* Boot parameters must start with a BP_TAG_FIRST tag. */
|
|
|
|
if (tag->id != BP_TAG_FIRST) {
|
|
printk(KERN_WARNING "Invalid boot parameters!\n");
|
|
return 0;
|
|
}
|
|
|
|
tag = (bp_tag_t*)((unsigned long)tag + sizeof(bp_tag_t) + tag->size);
|
|
|
|
/* Parse all tags. */
|
|
|
|
while (tag != NULL && tag->id != BP_TAG_LAST) {
|
|
for (t = &__tagtable_begin; t < &__tagtable_end; t++) {
|
|
if (tag->id == t->tag) {
|
|
t->parse(tag);
|
|
break;
|
|
}
|
|
}
|
|
if (t == &__tagtable_end)
|
|
printk(KERN_WARNING "Ignoring tag "
|
|
"0x%08x\n", tag->id);
|
|
tag = (bp_tag_t*)((unsigned long)(tag + 1) + tag->size);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Initialize architecture. (Early stage)
|
|
*/
|
|
|
|
void __init init_arch(bp_tag_t *bp_start)
|
|
{
|
|
|
|
#ifdef CONFIG_BLK_DEV_INITRD
|
|
initrd_start = &__initrd_start;
|
|
initrd_end = &__initrd_end;
|
|
#endif
|
|
|
|
sysmem.nr_banks = 0;
|
|
|
|
#ifdef CONFIG_CMDLINE_BOOL
|
|
strcpy(command_line, default_command_line);
|
|
#endif
|
|
|
|
/* Parse boot parameters */
|
|
|
|
if (bp_start)
|
|
parse_bootparam(bp_start);
|
|
|
|
if (sysmem.nr_banks == 0) {
|
|
sysmem.nr_banks = 1;
|
|
sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START;
|
|
sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START
|
|
+ PLATFORM_DEFAULT_MEM_SIZE;
|
|
}
|
|
|
|
/* Early hook for platforms */
|
|
|
|
platform_init(bp_start);
|
|
|
|
/* Initialize MMU. */
|
|
|
|
init_mmu();
|
|
}
|
|
|
|
/*
|
|
* Initialize system. Setup memory and reserve regions.
|
|
*/
|
|
|
|
extern char _end;
|
|
extern char _stext;
|
|
extern char _WindowVectors_text_start;
|
|
extern char _WindowVectors_text_end;
|
|
extern char _DebugInterruptVector_literal_start;
|
|
extern char _DebugInterruptVector_text_end;
|
|
extern char _KernelExceptionVector_literal_start;
|
|
extern char _KernelExceptionVector_text_end;
|
|
extern char _UserExceptionVector_literal_start;
|
|
extern char _UserExceptionVector_text_end;
|
|
extern char _DoubleExceptionVector_literal_start;
|
|
extern char _DoubleExceptionVector_text_end;
|
|
|
|
void __init setup_arch(char **cmdline_p)
|
|
{
|
|
extern int mem_reserve(unsigned long, unsigned long, int);
|
|
extern void bootmem_init(void);
|
|
|
|
memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
|
|
boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
|
|
*cmdline_p = command_line;
|
|
|
|
/* Reserve some memory regions */
|
|
|
|
#ifdef CONFIG_BLK_DEV_INITRD
|
|
if (initrd_start < initrd_end) {
|
|
initrd_is_mapped = mem_reserve(__pa(initrd_start),
|
|
__pa(initrd_end), 0);
|
|
initrd_below_start_ok = 1;
|
|
} else {
|
|
initrd_start = 0;
|
|
}
|
|
#endif
|
|
|
|
mem_reserve(__pa(&_stext),__pa(&_end), 1);
|
|
|
|
mem_reserve(__pa(&_WindowVectors_text_start),
|
|
__pa(&_WindowVectors_text_end), 0);
|
|
|
|
mem_reserve(__pa(&_DebugInterruptVector_literal_start),
|
|
__pa(&_DebugInterruptVector_text_end), 0);
|
|
|
|
mem_reserve(__pa(&_KernelExceptionVector_literal_start),
|
|
__pa(&_KernelExceptionVector_text_end), 0);
|
|
|
|
mem_reserve(__pa(&_UserExceptionVector_literal_start),
|
|
__pa(&_UserExceptionVector_text_end), 0);
|
|
|
|
mem_reserve(__pa(&_DoubleExceptionVector_literal_start),
|
|
__pa(&_DoubleExceptionVector_text_end), 0);
|
|
|
|
bootmem_init();
|
|
|
|
platform_setup(cmdline_p);
|
|
|
|
|
|
paging_init();
|
|
|
|
#ifdef CONFIG_VT
|
|
# if defined(CONFIG_VGA_CONSOLE)
|
|
conswitchp = &vga_con;
|
|
# elif defined(CONFIG_DUMMY_CONSOLE)
|
|
conswitchp = &dummy_con;
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef CONFIG_PCI
|
|
platform_pcibios_init();
|
|
#endif
|
|
}
|
|
|
|
void machine_restart(char * cmd)
|
|
{
|
|
platform_restart();
|
|
}
|
|
|
|
void machine_halt(void)
|
|
{
|
|
platform_halt();
|
|
while (1);
|
|
}
|
|
|
|
void machine_power_off(void)
|
|
{
|
|
platform_power_off();
|
|
while (1);
|
|
}
|
|
#ifdef CONFIG_PROC_FS
|
|
|
|
/*
|
|
* Display some core information through /proc/cpuinfo.
|
|
*/
|
|
|
|
static int
|
|
c_show(struct seq_file *f, void *slot)
|
|
{
|
|
/* high-level stuff */
|
|
seq_printf(f,"processor\t: 0\n"
|
|
"vendor_id\t: Tensilica\n"
|
|
"model\t\t: Xtensa " XCHAL_HW_VERSION_NAME "\n"
|
|
"core ID\t\t: " XCHAL_CORE_ID "\n"
|
|
"build ID\t: 0x%x\n"
|
|
"byte order\t: %s\n"
|
|
"cpu MHz\t\t: %lu.%02lu\n"
|
|
"bogomips\t: %lu.%02lu\n",
|
|
XCHAL_BUILD_UNIQUE_ID,
|
|
XCHAL_HAVE_BE ? "big" : "little",
|
|
CCOUNT_PER_JIFFY/(1000000/HZ),
|
|
(CCOUNT_PER_JIFFY/(10000/HZ)) % 100,
|
|
loops_per_jiffy/(500000/HZ),
|
|
(loops_per_jiffy/(5000/HZ)) % 100);
|
|
|
|
seq_printf(f,"flags\t\t: "
|
|
#if XCHAL_HAVE_NMI
|
|
"nmi "
|
|
#endif
|
|
#if XCHAL_HAVE_DEBUG
|
|
"debug "
|
|
# if XCHAL_HAVE_OCD
|
|
"ocd "
|
|
# endif
|
|
#endif
|
|
#if XCHAL_HAVE_DENSITY
|
|
"density "
|
|
#endif
|
|
#if XCHAL_HAVE_BOOLEANS
|
|
"boolean "
|
|
#endif
|
|
#if XCHAL_HAVE_LOOPS
|
|
"loop "
|
|
#endif
|
|
#if XCHAL_HAVE_NSA
|
|
"nsa "
|
|
#endif
|
|
#if XCHAL_HAVE_MINMAX
|
|
"minmax "
|
|
#endif
|
|
#if XCHAL_HAVE_SEXT
|
|
"sext "
|
|
#endif
|
|
#if XCHAL_HAVE_CLAMPS
|
|
"clamps "
|
|
#endif
|
|
#if XCHAL_HAVE_MAC16
|
|
"mac16 "
|
|
#endif
|
|
#if XCHAL_HAVE_MUL16
|
|
"mul16 "
|
|
#endif
|
|
#if XCHAL_HAVE_MUL32
|
|
"mul32 "
|
|
#endif
|
|
#if XCHAL_HAVE_MUL32_HIGH
|
|
"mul32h "
|
|
#endif
|
|
#if XCHAL_HAVE_FP
|
|
"fpu "
|
|
#endif
|
|
"\n");
|
|
|
|
/* Registers. */
|
|
seq_printf(f,"physical aregs\t: %d\n"
|
|
"misc regs\t: %d\n"
|
|
"ibreak\t\t: %d\n"
|
|
"dbreak\t\t: %d\n",
|
|
XCHAL_NUM_AREGS,
|
|
XCHAL_NUM_MISC_REGS,
|
|
XCHAL_NUM_IBREAK,
|
|
XCHAL_NUM_DBREAK);
|
|
|
|
|
|
/* Interrupt. */
|
|
seq_printf(f,"num ints\t: %d\n"
|
|
"ext ints\t: %d\n"
|
|
"int levels\t: %d\n"
|
|
"timers\t\t: %d\n"
|
|
"debug level\t: %d\n",
|
|
XCHAL_NUM_INTERRUPTS,
|
|
XCHAL_NUM_EXTINTERRUPTS,
|
|
XCHAL_NUM_INTLEVELS,
|
|
XCHAL_NUM_TIMERS,
|
|
XCHAL_DEBUGLEVEL);
|
|
|
|
/* Cache */
|
|
seq_printf(f,"icache line size: %d\n"
|
|
"icache ways\t: %d\n"
|
|
"icache size\t: %d\n"
|
|
"icache flags\t: "
|
|
#if XCHAL_ICACHE_LINE_LOCKABLE
|
|
"lock"
|
|
#endif
|
|
"\n"
|
|
"dcache line size: %d\n"
|
|
"dcache ways\t: %d\n"
|
|
"dcache size\t: %d\n"
|
|
"dcache flags\t: "
|
|
#if XCHAL_DCACHE_IS_WRITEBACK
|
|
"writeback"
|
|
#endif
|
|
#if XCHAL_DCACHE_LINE_LOCKABLE
|
|
"lock"
|
|
#endif
|
|
"\n",
|
|
XCHAL_ICACHE_LINESIZE,
|
|
XCHAL_ICACHE_WAYS,
|
|
XCHAL_ICACHE_SIZE,
|
|
XCHAL_DCACHE_LINESIZE,
|
|
XCHAL_DCACHE_WAYS,
|
|
XCHAL_DCACHE_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* We show only CPU #0 info.
|
|
*/
|
|
static void *
|
|
c_start(struct seq_file *f, loff_t *pos)
|
|
{
|
|
return (void *) ((*pos == 0) ? (void *)1 : NULL);
|
|
}
|
|
|
|
static void *
|
|
c_next(struct seq_file *f, void *v, loff_t *pos)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
c_stop(struct seq_file *f, void *v)
|
|
{
|
|
}
|
|
|
|
struct seq_operations cpuinfo_op =
|
|
{
|
|
start: c_start,
|
|
next: c_next,
|
|
stop: c_stop,
|
|
show: c_show
|
|
};
|
|
|
|
#endif /* CONFIG_PROC_FS */
|
|
|