| /* Boot entry point for MN10300 kernel | |
| * | |
| * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. | |
| * Written by David Howells (dhowells@redhat.com) | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public Licence | |
| * as published by the Free Software Foundation; either version | |
| * 2 of the Licence, or (at your option) any later version. | |
| */ | |
| #include <linux/init.h> | |
| #include <linux/threads.h> | |
| #include <linux/linkage.h> | |
| #include <linux/serial_reg.h> | |
| #include <asm/thread_info.h> | |
| #include <asm/page.h> | |
| #include <asm/pgtable.h> | |
| #include <asm/frame.inc> | |
| #include <asm/param.h> | |
| #include <unit/serial.h> | |
| #ifdef CONFIG_SMP | |
| #include <asm/smp.h> | |
| #include <asm/intctl-regs.h> | |
| #include <asm/cpu-regs.h> | |
| #include <proc/smp-regs.h> | |
| #endif /* CONFIG_SMP */ | |
| __HEAD | |
| ############################################################################### | |
| # | |
| # bootloader entry point | |
| # | |
| ############################################################################### | |
| .globl _start | |
| .type _start,@function | |
| _start: | |
| #ifdef CONFIG_SMP | |
| # | |
| # If this is a secondary CPU (AP), then deal with that elsewhere | |
| # | |
| mov (CPUID),d3 | |
| and CPUID_MASK,d3 | |
| bne startup_secondary | |
| # | |
| # We're dealing with the primary CPU (BP) here, then. | |
| # Keep BP's D0,D1,D2 register for boot check. | |
| # | |
| # Set up the Boot IPI for each secondary CPU | |
| mov 0x1,a0 | |
| loop_set_secondary_icr: | |
| mov a0,a1 | |
| asl CROSS_ICR_CPU_SHIFT,a1 | |
| add CROSS_GxICR(SMP_BOOT_IRQ,0),a1 | |
| movhu (a1),d3 | |
| or GxICR_ENABLE|GxICR_LEVEL_0,d3 | |
| movhu d3,(a1) | |
| movhu (a1),d3 # flush | |
| inc a0 | |
| cmp NR_CPUS,a0 | |
| bne loop_set_secondary_icr | |
| #endif /* CONFIG_SMP */ | |
| # save commandline pointer | |
| mov d0,a3 | |
| # preload the PGD pointer register | |
| mov swapper_pg_dir,d0 | |
| mov d0,(PTBR) | |
| clr d0 | |
| movbu d0,(PIDR) | |
| # turn on the TLBs | |
| mov MMUCTR_IIV|MMUCTR_DIV,d0 | |
| mov d0,(MMUCTR) | |
| #ifdef CONFIG_AM34_2 | |
| mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE|MMUCTR_WTE,d0 | |
| #else | |
| mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0 | |
| #endif | |
| mov d0,(MMUCTR) | |
| # turn on AM33v2 exception handling mode and set the trap table base | |
| movhu (CPUP),d0 | |
| or CPUP_EXM_AM33V2,d0 | |
| movhu d0,(CPUP) | |
| mov CONFIG_INTERRUPT_VECTOR_BASE,d0 | |
| mov d0,(TBR) | |
| # invalidate and enable both of the caches | |
| #ifdef CONFIG_SMP | |
| mov ECHCTR,a0 | |
| clr d0 | |
| mov d0,(a0) | |
| #endif | |
| mov CHCTR,a0 | |
| clr d0 | |
| movhu d0,(a0) # turn off first | |
| mov CHCTR_ICINV|CHCTR_DCINV,d0 | |
| movhu d0,(a0) | |
| setlb | |
| mov (a0),d0 | |
| btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy | |
| lne | |
| #ifdef CONFIG_MN10300_CACHE_ENABLED | |
| #ifdef CONFIG_MN10300_CACHE_WBACK | |
| #ifndef CONFIG_MN10300_CACHE_WBACK_NOWRALLOC | |
| mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0 | |
| #else | |
| mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK|CHCTR_DCALMD,d0 | |
| #endif /* NOWRALLOC */ | |
| #else | |
| mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0 | |
| #endif /* WBACK */ | |
| movhu d0,(a0) # enable | |
| #endif /* ENABLED */ | |
| # turn on RTS on the debug serial port if applicable | |
| #ifdef CONFIG_MN10300_UNIT_ASB2305 | |
| bset UART_MCR_RTS,(ASB2305_DEBUG_MCR) | |
| #endif | |
| # clear the BSS area | |
| mov __bss_start,a0 | |
| mov __bss_stop,a1 | |
| clr d0 | |
| bssclear: | |
| cmp a1,a0 | |
| bge bssclear_end | |
| mov d0,(a0) | |
| inc4 a0 | |
| bra bssclear | |
| bssclear_end: | |
| # retrieve the parameters (including command line) before we overwrite | |
| # them | |
| cmp 0xabadcafe,d1 | |
| bne __no_parameters | |
| __copy_parameters: | |
| mov redboot_command_line,a0 | |
| mov a0,a1 | |
| add COMMAND_LINE_SIZE,a1 | |
| 1: | |
| movbu (a3),d0 | |
| inc a3 | |
| movbu d0,(a0) | |
| inc a0 | |
| cmp a1,a0 | |
| blt 1b | |
| mov redboot_platform_name,a0 | |
| mov a0,a1 | |
| add COMMAND_LINE_SIZE,a1 | |
| mov d2,a3 | |
| 1: | |
| movbu (a3),d0 | |
| inc a3 | |
| movbu d0,(a0) | |
| inc a0 | |
| cmp a1,a0 | |
| blt 1b | |
| __no_parameters: | |
| # set up the registers with recognisable rubbish in them | |
| mov init_thread_union+THREAD_SIZE-12,sp | |
| mov 0xea01eaea,d0 | |
| mov d0,(4,sp) # EPSW save area | |
| mov 0xea02eaea,d0 | |
| mov d0,(8,sp) # PC save area | |
| mov 0xeb0060ed,d0 | |
| mov d0,mdr | |
| mov 0xeb0061ed,d0 | |
| mov d0,mdrq | |
| mov 0xeb0062ed,d0 | |
| mov d0,mcrh | |
| mov 0xeb0063ed,d0 | |
| mov d0,mcrl | |
| mov 0xeb0064ed,d0 | |
| mov d0,mcvf | |
| mov 0xed0065ed,a3 | |
| mov a3,usp | |
| mov 0xed00e0ed,e0 | |
| mov 0xed00e1ed,e1 | |
| mov 0xed00e2ed,e2 | |
| mov 0xed00e3ed,e3 | |
| mov 0xed00e4ed,e4 | |
| mov 0xed00e5ed,e5 | |
| mov 0xed00e6ed,e6 | |
| mov 0xed00e7ed,e7 | |
| mov 0xed00d0ed,d0 | |
| mov 0xed00d1ed,d1 | |
| mov 0xed00d2ed,d2 | |
| mov 0xed00d3ed,d3 | |
| mov 0xed00a0ed,a0 | |
| mov 0xed00a1ed,a1 | |
| mov 0xed00a2ed,a2 | |
| mov 0,a3 | |
| # set up the initial kernel stack | |
| SAVE_ALL | |
| mov 0xffffffff,d0 | |
| mov d0,(REG_ORIG_D0,fp) | |
| # put different recognisable rubbish in the regs | |
| mov 0xfb0060ed,d0 | |
| mov d0,mdr | |
| mov 0xfb0061ed,d0 | |
| mov d0,mdrq | |
| mov 0xfb0062ed,d0 | |
| mov d0,mcrh | |
| mov 0xfb0063ed,d0 | |
| mov d0,mcrl | |
| mov 0xfb0064ed,d0 | |
| mov d0,mcvf | |
| mov 0xfd0065ed,a0 | |
| mov a0,usp | |
| mov 0xfd00e0ed,e0 | |
| mov 0xfd00e1ed,e1 | |
| mov 0xfd00e2ed,e2 | |
| mov 0xfd00e3ed,e3 | |
| mov 0xfd00e4ed,e4 | |
| mov 0xfd00e5ed,e5 | |
| mov 0xfd00e6ed,e6 | |
| mov 0xfd00e7ed,e7 | |
| mov 0xfd00d0ed,d0 | |
| mov 0xfd00d1ed,d1 | |
| mov 0xfd00d2ed,d2 | |
| mov 0xfd00d3ed,d3 | |
| mov 0xfd00a0ed,a0 | |
| mov 0xfd00a1ed,a1 | |
| mov 0xfd00a2ed,a2 | |
| # we may be holding current in E2 | |
| #ifdef CONFIG_MN10300_CURRENT_IN_E2 | |
| mov init_task,e2 | |
| #endif | |
| # initialise the processor and the unit | |
| call processor_init[],0 | |
| call unit_init[],0 | |
| #ifdef CONFIG_SMP | |
| # mark the primary CPU in cpu_boot_map | |
| mov cpu_boot_map,a0 | |
| mov 0x1,d0 | |
| mov d0,(a0) | |
| # signal each secondary CPU to begin booting | |
| mov 0x1,d2 # CPU ID | |
| loop_request_boot_secondary: | |
| mov d2,a0 | |
| # send SMP_BOOT_IPI to secondary CPU | |
| asl CROSS_ICR_CPU_SHIFT,a0 | |
| add CROSS_GxICR(SMP_BOOT_IRQ,0),a0 | |
| movhu (a0),d0 | |
| or GxICR_REQUEST|GxICR_DETECT,d0 | |
| movhu d0,(a0) | |
| movhu (a0),d0 # flush | |
| # wait up to 100ms for AP's IPI to be received | |
| clr d3 | |
| wait_on_secondary_boot: | |
| mov DELAY_TIME_BOOT_IPI,d0 | |
| call __delay[],0 | |
| inc d3 | |
| mov cpu_boot_map,a0 | |
| mov (a0),d0 | |
| lsr d2,d0 | |
| btst 0x1,d0 | |
| bne 1f | |
| cmp TIME_OUT_COUNT_BOOT_IPI,d3 | |
| bne wait_on_secondary_boot | |
| 1: | |
| inc d2 | |
| cmp NR_CPUS,d2 | |
| bne loop_request_boot_secondary | |
| #endif /* CONFIG_SMP */ | |
| #ifdef CONFIG_GDBSTUB | |
| call gdbstub_init[],0 | |
| #ifdef CONFIG_GDBSTUB_IMMEDIATE | |
| .globl __gdbstub_pause | |
| __gdbstub_pause: | |
| bra __gdbstub_pause | |
| #endif | |
| #endif | |
| jmp start_kernel | |
| .size _start,.-_start | |
| ############################################################################### | |
| # | |
| # Secondary CPU boot point | |
| # | |
| ############################################################################### | |
| #ifdef CONFIG_SMP | |
| startup_secondary: | |
| # preload the PGD pointer register | |
| mov swapper_pg_dir,d0 | |
| mov d0,(PTBR) | |
| clr d0 | |
| movbu d0,(PIDR) | |
| # turn on the TLBs | |
| mov MMUCTR_IIV|MMUCTR_DIV,d0 | |
| mov d0,(MMUCTR) | |
| #ifdef CONFIG_AM34_2 | |
| mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE|MMUCTR_WTE,d0 | |
| #else | |
| mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0 | |
| #endif | |
| mov d0,(MMUCTR) | |
| # turn on AM33v2 exception handling mode and set the trap table base | |
| movhu (CPUP),d0 | |
| or CPUP_EXM_AM33V2,d0 | |
| movhu d0,(CPUP) | |
| # set the interrupt vector table | |
| mov CONFIG_INTERRUPT_VECTOR_BASE,d0 | |
| mov d0,(TBR) | |
| # invalidate and enable both of the caches | |
| mov ECHCTR,a0 | |
| clr d0 | |
| mov d0,(a0) | |
| mov CHCTR,a0 | |
| clr d0 | |
| movhu d0,(a0) # turn off first | |
| mov CHCTR_ICINV|CHCTR_DCINV,d0 | |
| movhu d0,(a0) | |
| setlb | |
| mov (a0),d0 | |
| btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy (use CPU loop buffer) | |
| lne | |
| #ifdef CONFIG_MN10300_CACHE_ENABLED | |
| #ifdef CONFIG_MN10300_CACHE_WBACK | |
| #ifndef CONFIG_MN10300_CACHE_WBACK_NOWRALLOC | |
| mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0 | |
| #else | |
| mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK|CHCTR_DCALMD,d0 | |
| #endif /* !NOWRALLOC */ | |
| #else | |
| mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0 | |
| #endif /* WBACK */ | |
| movhu d0,(a0) # enable | |
| #endif /* ENABLED */ | |
| # Clear the boot IPI interrupt for this CPU | |
| movhu (GxICR(SMP_BOOT_IRQ)),d0 | |
| and ~GxICR_REQUEST,d0 | |
| movhu d0,(GxICR(SMP_BOOT_IRQ)) | |
| movhu (GxICR(SMP_BOOT_IRQ)),d0 # flush | |
| /* get stack */ | |
| mov CONFIG_INTERRUPT_VECTOR_BASE + CONFIG_BOOT_STACK_OFFSET,a0 | |
| mov (CPUID),d0 | |
| and CPUID_MASK,d0 | |
| mulu CONFIG_BOOT_STACK_SIZE,d0 | |
| sub d0,a0 | |
| mov a0,sp | |
| # init interrupt for AP | |
| call smp_prepare_cpu_init[],0 | |
| # mark this secondary CPU in cpu_boot_map | |
| mov (CPUID),d0 | |
| mov 0x1,d1 | |
| asl d0,d1 | |
| mov cpu_boot_map,a0 | |
| bset d1,(a0) | |
| or EPSW_IE|EPSW_IM_1,epsw # permit level 0 interrupts | |
| nop | |
| nop | |
| #ifdef CONFIG_MN10300_CACHE_WBACK | |
| # flush the local cache if it's in writeback mode | |
| call mn10300_local_dcache_flush_inv[],0 | |
| setlb | |
| mov (CHCTR),d0 | |
| btst CHCTR_DCBUSY,d0 # wait till not busy (use CPU loop buffer) | |
| lne | |
| #endif | |
| # now sleep waiting for further instructions | |
| secondary_sleep: | |
| mov CPUM_SLEEP,d0 | |
| movhu d0,(CPUM) | |
| nop | |
| nop | |
| bra secondary_sleep | |
| .size startup_secondary,.-startup_secondary | |
| #endif /* CONFIG_SMP */ | |
| ############################################################################### | |
| # | |
| # | |
| # | |
| ############################################################################### | |
| ENTRY(__head_end) | |
| /* | |
| * This is initialized to disallow all access to the low 2G region | |
| * - the high 2G region is managed directly by the MMU | |
| * - range 0x70000000-0x7C000000 are initialised for use by VMALLOC | |
| */ | |
| .section .bss | |
| .balign PAGE_SIZE | |
| ENTRY(swapper_pg_dir) | |
| .space PTRS_PER_PGD*4 | |
| /* | |
| * The page tables are initialized to only 8MB here - the final page | |
| * tables are set up later depending on memory size. | |
| */ | |
| .balign PAGE_SIZE | |
| ENTRY(empty_zero_page) | |
| .space PAGE_SIZE | |
| .balign PAGE_SIZE | |
| ENTRY(empty_bad_page) | |
| .space PAGE_SIZE | |
| .balign PAGE_SIZE | |
| ENTRY(empty_bad_pte_table) | |
| .space PAGE_SIZE | |
| .balign PAGE_SIZE | |
| ENTRY(large_page_table) | |
| .space PAGE_SIZE | |
| .balign PAGE_SIZE | |
| ENTRY(kernel_vmalloc_ptes) | |
| .space ((VMALLOC_END-VMALLOC_START)/PAGE_SIZE)*4 |