2011-09-19 17:44:52 +00:00
/*
* PowerNV setup code .
*
* Copyright 2011 IBM Corp .
*
* 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 .
*/
# undef DEBUG
# include <linux/cpu.h>
# include <linux/errno.h>
# include <linux/sched.h>
# include <linux/kernel.h>
# include <linux/tty.h>
# include <linux/reboot.h>
# include <linux/init.h>
# include <linux/console.h>
# include <linux/delay.h>
# include <linux/irq.h>
# include <linux/seq_file.h>
# include <linux/of.h>
# include <linux/interrupt.h>
# include <linux/bug.h>
# include <asm/machdep.h>
# include <asm/firmware.h>
# include <asm/xics.h>
2011-09-19 17:45:01 +00:00
# include <asm/rtas.h>
2011-09-19 17:44:59 +00:00
# include <asm/opal.h>
2011-09-19 17:44:52 +00:00
# include "powernv.h"
static void __init pnv_setup_arch ( void )
{
/* Initialize SMP */
pnv_smp_init ( ) ;
2011-09-19 17:45:05 +00:00
/* Setup PCI */
pnv_pci_init ( ) ;
2011-09-19 17:44:52 +00:00
2011-09-19 17:45:01 +00:00
/* Setup RTC and NVRAM callbacks */
if ( firmware_has_feature ( FW_FEATURE_OPAL ) )
opal_nvram_init ( ) ;
2011-09-19 17:44:52 +00:00
/* Enable NAP mode */
powersave_nap = 1 ;
/* XXX PMCS */
}
static void __init pnv_init_early ( void )
{
2011-09-19 17:44:59 +00:00
# ifdef CONFIG_HVC_OPAL
if ( firmware_has_feature ( FW_FEATURE_OPAL ) )
hvc_opal_init_early ( ) ;
else
# endif
add_preferred_console ( " hvc " , 0 , NULL ) ;
2011-09-19 17:44:52 +00:00
}
static void __init pnv_init_IRQ ( void )
{
xics_init ( ) ;
WARN_ON ( ! ppc_md . get_irq ) ;
}
static void pnv_show_cpuinfo ( struct seq_file * m )
{
struct device_node * root ;
const char * model = " " ;
root = of_find_node_by_path ( " / " ) ;
if ( root )
model = of_get_property ( root , " model " , NULL ) ;
seq_printf ( m , " machine \t \t : PowerNV %s \n " , model ) ;
2013-05-14 15:10:02 +10:00
if ( firmware_has_feature ( FW_FEATURE_OPALv3 ) )
seq_printf ( m , " firmware \t : OPAL v3 \n " ) ;
else if ( firmware_has_feature ( FW_FEATURE_OPALv2 ) )
2011-09-19 17:44:57 +00:00
seq_printf ( m , " firmware \t : OPAL v2 \n " ) ;
else if ( firmware_has_feature ( FW_FEATURE_OPAL ) )
seq_printf ( m , " firmware \t : OPAL v1 \n " ) ;
else
seq_printf ( m , " firmware \t : BML \n " ) ;
2011-09-19 17:44:52 +00:00
of_node_put ( root ) ;
}
2011-09-19 18:28:03 +00:00
static void __noreturn pnv_restart ( char * cmd )
2011-09-19 17:44:52 +00:00
{
2011-09-19 18:28:03 +00:00
long rc = OPAL_BUSY ;
2013-06-20 18:13:23 +08:00
opal_notifier_disable ( ) ;
2011-09-19 18:28:03 +00:00
while ( rc = = OPAL_BUSY | | rc = = OPAL_BUSY_EVENT ) {
rc = opal_cec_reboot ( ) ;
if ( rc = = OPAL_BUSY_EVENT )
opal_poll_events ( NULL ) ;
else
mdelay ( 10 ) ;
}
for ( ; ; )
opal_poll_events ( NULL ) ;
2011-09-19 17:44:52 +00:00
}
2011-09-19 18:28:03 +00:00
static void __noreturn pnv_power_off ( void )
2011-09-19 17:44:52 +00:00
{
2011-09-19 18:28:03 +00:00
long rc = OPAL_BUSY ;
2013-06-20 18:13:23 +08:00
opal_notifier_disable ( ) ;
2011-09-19 18:28:03 +00:00
while ( rc = = OPAL_BUSY | | rc = = OPAL_BUSY_EVENT ) {
rc = opal_cec_power_down ( 0 ) ;
if ( rc = = OPAL_BUSY_EVENT )
opal_poll_events ( NULL ) ;
else
mdelay ( 10 ) ;
}
for ( ; ; )
opal_poll_events ( NULL ) ;
2011-09-19 17:44:52 +00:00
}
2011-09-19 18:28:03 +00:00
static void __noreturn pnv_halt ( void )
2011-09-19 17:44:52 +00:00
{
2011-09-19 18:28:03 +00:00
pnv_power_off ( ) ;
2011-09-19 17:44:52 +00:00
}
2011-09-19 17:45:01 +00:00
static void pnv_progress ( char * s , unsigned short hex )
2011-09-19 17:44:52 +00:00
{
}
2013-05-10 16:59:18 +10:00
static void pnv_shutdown ( void )
{
/* Let the PCI code clear up IODA tables */
pnv_pci_shutdown ( ) ;
/* And unregister all OPAL interrupts so they don't fire
* up while we kexec
*/
opal_shutdown ( ) ;
}
2011-09-19 17:45:01 +00:00
# ifdef CONFIG_KEXEC
static void pnv_kexec_cpu_down ( int crash_shutdown , int secondary )
2011-09-19 17:44:52 +00:00
{
2011-09-19 17:45:01 +00:00
xics_kexec_teardown_cpu ( secondary ) ;
2011-09-19 17:44:52 +00:00
}
2011-09-19 17:45:01 +00:00
# endif /* CONFIG_KEXEC */
2011-09-19 17:44:52 +00:00
2011-09-19 17:45:01 +00:00
static void __init pnv_setup_machdep_opal ( void )
2011-09-19 17:44:52 +00:00
{
2011-09-19 17:45:01 +00:00
ppc_md . get_boot_time = opal_get_boot_time ;
ppc_md . get_rtc_time = opal_get_rtc_time ;
ppc_md . set_rtc_time = opal_set_rtc_time ;
ppc_md . restart = pnv_restart ;
ppc_md . power_off = pnv_power_off ;
ppc_md . halt = pnv_halt ;
2011-09-19 17:45:04 +00:00
ppc_md . machine_check_exception = opal_machine_check ;
2011-09-19 17:44:52 +00:00
}
2011-09-19 17:45:01 +00:00
# ifdef CONFIG_PPC_POWERNV_RTAS
static void __init pnv_setup_machdep_rtas ( void )
2011-09-19 17:44:52 +00:00
{
2011-09-19 17:45:01 +00:00
if ( rtas_token ( " get-time-of-day " ) ! = RTAS_UNKNOWN_SERVICE ) {
ppc_md . get_boot_time = rtas_get_boot_time ;
ppc_md . get_rtc_time = rtas_get_rtc_time ;
ppc_md . set_rtc_time = rtas_set_rtc_time ;
}
ppc_md . restart = rtas_restart ;
ppc_md . power_off = rtas_power_off ;
ppc_md . halt = rtas_halt ;
2011-09-19 17:44:52 +00:00
}
2011-09-19 17:45:01 +00:00
# endif /* CONFIG_PPC_POWERNV_RTAS */
2011-09-19 17:44:52 +00:00
static int __init pnv_probe ( void )
{
unsigned long root = of_get_flat_dt_root ( ) ;
if ( ! of_flat_dt_is_compatible ( root , " ibm,powernv " ) )
return 0 ;
hpte_init_native ( ) ;
2011-09-19 17:45:01 +00:00
if ( firmware_has_feature ( FW_FEATURE_OPAL ) )
pnv_setup_machdep_opal ( ) ;
# ifdef CONFIG_PPC_POWERNV_RTAS
else if ( rtas . base )
pnv_setup_machdep_rtas ( ) ;
# endif /* CONFIG_PPC_POWERNV_RTAS */
2011-09-19 17:44:52 +00:00
pr_debug ( " PowerNV detected ! \n " ) ;
return 1 ;
}
define_machine ( powernv ) {
. name = " PowerNV " ,
. probe = pnv_probe ,
. init_early = pnv_init_early ,
2011-09-19 17:45:01 +00:00
. setup_arch = pnv_setup_arch ,
2011-09-19 17:44:52 +00:00
. init_IRQ = pnv_init_IRQ ,
. show_cpuinfo = pnv_show_cpuinfo ,
. progress = pnv_progress ,
2013-05-10 16:59:18 +10:00
. machine_shutdown = pnv_shutdown ,
2011-09-19 17:44:52 +00:00
. power_save = power7_idle ,
. calibrate_decr = generic_calibrate_decr ,
# ifdef CONFIG_KEXEC
. kexec_cpu_down = pnv_kexec_cpu_down ,
# endif
} ;