2005-10-06 06:06:20 +04:00
/*
* Common prep / pmac / chrp boot and setup code .
*/
# include <linux/module.h>
# include <linux/string.h>
# include <linux/sched.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/reboot.h>
# include <linux/delay.h>
# include <linux/initrd.h>
# include <linux/tty.h>
# include <linux/seq_file.h>
# include <linux/root_dev.h>
# include <linux/cpu.h>
# include <linux/console.h>
2010-07-12 08:36:09 +04:00
# include <linux/memblock.h>
2016-01-14 07:33:46 +03:00
# include <linux/export.h>
2005-10-06 06:06:20 +04:00
# include <asm/io.h>
# include <asm/prom.h>
# include <asm/processor.h>
# include <asm/pgtable.h>
# include <asm/setup.h>
# include <asm/smp.h>
# include <asm/elf.h>
# include <asm/cputable.h>
# include <asm/bootx.h>
# include <asm/btext.h>
# include <asm/machdep.h>
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2005-10-06 06:06:20 +04:00
# include <asm/pmac_feature.h>
# include <asm/sections.h>
# include <asm/nvram.h>
# include <asm/xmon.h>
2005-10-26 08:57:33 +04:00
# include <asm/time.h>
2005-11-23 09:56:06 +03:00
# include <asm/serial.h>
2005-11-23 09:57:25 +03:00
# include <asm/udbg.h>
2015-09-16 13:04:51 +03:00
# include <asm/code-patching.h>
2016-07-23 12:12:40 +03:00
# include <asm/cpu_has_feature.h>
2018-03-08 14:31:59 +03:00
# include <asm/asm-prototypes.h>
2018-07-05 19:24:51 +03:00
# include <asm/kdump.h>
2005-10-06 06:06:20 +04:00
2005-10-26 11:11:18 +04:00
# define DBG(fmt...)
2005-10-06 06:06:20 +04:00
extern void bootx_init ( unsigned long r4 , unsigned long phys ) ;
2005-10-27 16:42:04 +04:00
int boot_cpuid_phys ;
2011-07-16 07:22:13 +04:00
EXPORT_SYMBOL_GPL ( boot_cpuid_phys ) ;
2005-10-27 16:42:04 +04:00
2008-12-10 17:28:41 +03:00
int smp_hw_index [ NR_CPUS ] ;
2016-01-14 07:33:46 +03:00
EXPORT_SYMBOL ( smp_hw_index ) ;
2008-12-10 17:28:41 +03:00
2005-10-06 06:06:20 +04:00
unsigned long ISA_DMA_THRESHOLD ;
unsigned int DMA_MODE_READ ;
unsigned int DMA_MODE_WRITE ;
2016-01-14 07:33:46 +03:00
EXPORT_SYMBOL ( ISA_DMA_THRESHOLD ) ;
EXPORT_SYMBOL ( DMA_MODE_READ ) ;
EXPORT_SYMBOL ( DMA_MODE_WRITE ) ;
2005-10-06 06:06:20 +04:00
/*
2016-07-05 08:03:45 +03:00
* We ' re called here very early in the boot .
2005-10-06 06:06:20 +04:00
*
* Note that the kernel may be running at an address which is different
* from the address that it was linked at , so we must use RELOC / PTRRELOC
* to access static data ( including strings ) . - - paulus
*/
2008-05-15 07:49:44 +04:00
notrace unsigned long __init early_init ( unsigned long dt_ptr )
2005-10-06 06:06:20 +04:00
{
unsigned long offset = reloc_offset ( ) ;
2005-10-17 14:13:47 +04:00
/* First zero the BSS -- use memset_io, some platforms don't have
* caches on yet */
2006-10-26 03:36:49 +04:00
memset_io ( ( void __iomem * ) PTRRELOC ( & __bss_start ) , 0 ,
__bss_stop - __bss_start ) ;
2005-10-17 14:13:47 +04:00
2005-10-06 06:06:20 +04:00
/*
* Identify the CPU type and fix up code sections
* that depend on which cpu we have .
*/
2016-07-05 08:03:41 +03:00
identify_cpu ( offset , mfspr ( SPRN_PVR ) ) ;
2006-10-24 10:42:40 +04:00
2016-07-05 08:03:41 +03:00
apply_feature_fixups ( ) ;
2011-11-14 16:54:47 +04:00
2005-10-06 06:06:20 +04:00
return KERNELBASE + offset ;
}
/*
2016-07-05 08:03:45 +03:00
* This is run before start_kernel ( ) , the kernel has been relocated
* and we are running with enough of the MMU enabled to have our
* proper kernel virtual addresses
*
2016-08-10 10:32:38 +03:00
* We do the initial parsing of the flat device - tree and prepares
* for the MMU to be fully initialized .
2005-10-06 06:06:20 +04:00
*/
2015-09-16 13:04:53 +03:00
extern unsigned int memset_nocache_branch ; /* Insn to be replaced by NOP */
2011-07-25 15:29:33 +04:00
notrace void __init machine_init ( u64 dt_ptr )
2005-10-06 06:06:20 +04:00
{
2017-08-23 17:54:38 +03:00
unsigned int * addr = & memset_nocache_branch ;
unsigned long insn ;
2016-08-10 10:27:34 +03:00
/* Configure static keys first, now that we're relocated. */
setup_feature_keys ( ) ;
2007-02-13 07:54:22 +03:00
/* Enable early debugging if any specified (see udbg.h) */
udbg_early_init ( ) ;
2005-11-23 09:57:25 +03:00
2015-09-16 13:04:51 +03:00
patch_instruction ( ( unsigned int * ) & memcpy , PPC_INST_NOP ) ;
2017-08-23 17:54:38 +03:00
insn = create_cond_branch ( addr , branch_target ( addr ) , 0x820000 ) ;
patch_instruction ( addr , insn ) ; /* replace b by bne cr0 */
2015-09-16 13:04:51 +03:00
2005-11-23 09:57:25 +03:00
/* Do some early initialization based on the flat device tree */
2005-10-06 06:06:20 +04:00
early_init_devtree ( __va ( dt_ptr ) ) ;
2011-07-04 22:38:03 +04:00
early_init_mmu ( ) ;
2008-12-17 13:09:26 +03:00
setup_kdump_trampoline ( ) ;
2005-10-06 06:06:20 +04:00
}
/* Checks "l2cr=xxxx" command-line option */
2018-03-07 23:32:55 +03:00
static int __init ppc_setup_l2cr ( char * str )
2005-10-06 06:06:20 +04:00
{
if ( cpu_has_feature ( CPU_FTR_L2CR ) ) {
unsigned long val = simple_strtoul ( str , NULL , 0 ) ;
printk ( KERN_INFO " l2cr set to %lx \n " , val ) ;
_set_L2CR ( 0 ) ; /* force invalidate by disable cache */
_set_L2CR ( val ) ; /* and enable it */
}
return 1 ;
}
__setup ( " l2cr= " , ppc_setup_l2cr ) ;
2008-03-28 23:20:23 +03:00
/* Checks "l3cr=xxxx" command-line option */
2018-03-07 23:32:55 +03:00
static int __init ppc_setup_l3cr ( char * str )
2008-03-28 23:20:23 +03:00
{
if ( cpu_has_feature ( CPU_FTR_L3CR ) ) {
unsigned long val = simple_strtoul ( str , NULL , 0 ) ;
printk ( KERN_INFO " l3cr set to %lx \n " , val ) ;
_set_L3CR ( val ) ; /* and enable it */
}
return 1 ;
}
__setup ( " l3cr= " , ppc_setup_l3cr ) ;
2005-10-06 06:06:20 +04:00
# ifdef CONFIG_GENERIC_NVRAM
/* Generic nvram hooks used by drivers/char/gen_nvram.c */
unsigned char nvram_read_byte ( int addr )
{
if ( ppc_md . nvram_read_val )
return ppc_md . nvram_read_val ( addr ) ;
return 0xff ;
}
EXPORT_SYMBOL ( nvram_read_byte ) ;
void nvram_write_byte ( unsigned char val , int addr )
{
if ( ppc_md . nvram_write_val )
ppc_md . nvram_write_val ( addr , val ) ;
}
EXPORT_SYMBOL ( nvram_write_byte ) ;
2009-08-13 12:03:02 +04:00
ssize_t nvram_get_size ( void )
{
if ( ppc_md . nvram_size )
return ppc_md . nvram_size ( ) ;
return - 1 ;
}
EXPORT_SYMBOL ( nvram_get_size ) ;
2005-10-06 06:06:20 +04:00
void nvram_sync ( void )
{
if ( ppc_md . nvram_sync )
ppc_md . nvram_sync ( ) ;
}
EXPORT_SYMBOL ( nvram_sync ) ;
# endif /* CONFIG_NVRAM */
2018-03-07 23:32:55 +03:00
static int __init ppc_init ( void )
2005-10-06 06:06:20 +04:00
{
/* clear the progress line */
2007-03-27 09:40:28 +04:00
if ( ppc_md . progress )
ppc_md . progress ( " " , 0xffff ) ;
2005-10-06 06:06:20 +04:00
/* call platform init */
if ( ppc_md . init ! = NULL ) {
ppc_md . init ( ) ;
}
return 0 ;
}
arch_initcall ( ppc_init ) ;
2016-07-05 08:07:51 +03:00
void __init irqstack_early_init ( void )
2008-04-28 10:21:22 +04:00
{
unsigned int i ;
/* interrupt stacks must be in lowmem, we get that for free on ppc32
2010-07-07 02:39:01 +04:00
* as the memblock is limited to lowmem by default */
2008-04-28 10:21:22 +04:00
for_each_possible_cpu ( i ) {
softirq_ctx [ i ] = ( struct thread_info * )
2010-07-12 08:36:09 +04:00
__va ( memblock_alloc ( THREAD_SIZE , THREAD_SIZE ) ) ;
2008-04-28 10:21:22 +04:00
hardirq_ctx [ i ] = ( struct thread_info * )
2010-07-12 08:36:09 +04:00
__va ( memblock_alloc ( THREAD_SIZE , THREAD_SIZE ) ) ;
2008-04-28 10:21:22 +04:00
}
}
2008-04-30 12:49:55 +04:00
# if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
2016-07-05 08:07:51 +03:00
void __init exc_lvl_early_init ( void )
2008-04-30 12:49:55 +04:00
{
2010-08-18 10:44:25 +04:00
unsigned int i , hw_cpu ;
2008-04-30 12:49:55 +04:00
/* interrupt stacks must be in lowmem, we get that for free on ppc32
2010-07-12 08:36:09 +04:00
* as the memblock is limited to lowmem by MEMBLOCK_REAL_LIMIT */
2008-04-30 12:49:55 +04:00
for_each_possible_cpu ( i ) {
2014-01-29 14:24:54 +04:00
# ifdef CONFIG_SMP
2010-08-18 10:44:25 +04:00
hw_cpu = get_hard_smp_processor_id ( i ) ;
2014-01-29 14:24:54 +04:00
# else
hw_cpu = 0 ;
# endif
2010-08-18 10:44:25 +04:00
critirq_ctx [ hw_cpu ] = ( struct thread_info * )
2010-07-12 08:36:09 +04:00
__va ( memblock_alloc ( THREAD_SIZE , THREAD_SIZE ) ) ;
2008-04-30 12:49:55 +04:00
# ifdef CONFIG_BOOKE
2010-08-18 10:44:25 +04:00
dbgirq_ctx [ hw_cpu ] = ( struct thread_info * )
2010-07-12 08:36:09 +04:00
__va ( memblock_alloc ( THREAD_SIZE , THREAD_SIZE ) ) ;
2010-08-18 10:44:25 +04:00
mcheckirq_ctx [ hw_cpu ] = ( struct thread_info * )
2010-07-12 08:36:09 +04:00
__va ( memblock_alloc ( THREAD_SIZE , THREAD_SIZE ) ) ;
2008-04-30 12:49:55 +04:00
# endif
}
}
# endif
2016-07-05 08:07:51 +03:00
void __init setup_power_save ( void )
2016-07-05 08:04:05 +03:00
{
# ifdef CONFIG_6xx
if ( cpu_has_feature ( CPU_FTR_CAN_DOZE ) | |
cpu_has_feature ( CPU_FTR_CAN_NAP ) )
ppc_md . power_save = ppc6xx_idle ;
# endif
# ifdef CONFIG_E500
if ( cpu_has_feature ( CPU_FTR_CAN_DOZE ) | |
cpu_has_feature ( CPU_FTR_CAN_NAP ) )
ppc_md . power_save = e500_idle ;
# endif
}
2016-07-05 08:07:51 +03:00
__init void initialize_cache_info ( void )
2016-07-05 08:04:10 +03:00
{
/*
* Set cache line size based on type of cpu as a default .
* Systems with OF can look in the properties on the cpu node ( s )
* for a possibly more accurate value .
*/
dcache_bsize = cur_cpu_spec - > dcache_bsize ;
icache_bsize = cur_cpu_spec - > icache_bsize ;
ucache_bsize = 0 ;
if ( cpu_has_feature ( CPU_FTR_UNIFIED_ID_CACHE ) )
ucache_bsize = icache_bsize = dcache_bsize ;
}