2005-04-16 15:20:36 -07:00
/*
2005-10-29 22:07:56 +10:00
* Maple ( 970 eval board ) setup code
2005-04-16 15:20:36 -07:00
*
* ( c ) Copyright 2004 Benjamin Herrenschmidt ( benh @ kernel . crashing . org ) ,
* 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 .
*
*/
2006-07-03 17:22:05 +10:00
# undef DEBUG
2005-04-16 15:20:36 -07:00
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/sched.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/stddef.h>
# include <linux/unistd.h>
# include <linux/ptrace.h>
# include <linux/slab.h>
# include <linux/user.h>
# include <linux/tty.h>
# include <linux/string.h>
# include <linux/delay.h>
# include <linux/ioport.h>
# include <linux/major.h>
# include <linux/initrd.h>
# include <linux/vt_kern.h>
# include <linux/console.h>
# include <linux/pci.h>
# include <linux/adb.h>
# include <linux/cuda.h>
# include <linux/pmu.h>
# include <linux/irq.h>
# include <linux/seq_file.h>
# include <linux/root_dev.h>
# include <linux/serial.h>
# include <linux/smp.h>
2007-10-18 23:40:25 -07:00
# include <linux/bitops.h>
2008-01-08 05:07:15 +11:00
# include <linux/of_device.h>
2008-02-13 16:56:49 -08:00
# include <linux/lmb.h>
2005-04-16 15:20:36 -07:00
# include <asm/processor.h>
# include <asm/sections.h>
# include <asm/prom.h>
# include <asm/system.h>
# include <asm/pgtable.h>
# include <asm/io.h>
# include <asm/pci-bridge.h>
# include <asm/iommu.h>
# include <asm/machdep.h>
# include <asm/dma.h>
# include <asm/cputable.h>
# include <asm/time.h>
2005-09-27 13:51:59 +10:00
# include <asm/mpic.h>
2006-12-06 18:50:46 -06:00
# include <asm/rtas.h>
2005-10-10 22:50:37 +10:00
# include <asm/udbg.h>
2007-02-05 20:01:15 -06:00
# include <asm/nvram.h>
2005-04-16 15:20:36 -07:00
2005-10-29 22:07:56 +10:00
# include "maple.h"
2005-04-16 15:20:36 -07:00
# ifdef DEBUG
# define DBG(fmt...) udbg_printf(fmt)
# else
# define DBG(fmt...)
# endif
2006-01-14 16:35:35 +11:00
static unsigned long maple_find_nvram_base ( void )
{
struct device_node * rtcs ;
unsigned long result = 0 ;
/* find NVRAM device */
rtcs = of_find_compatible_node ( NULL , " nvram " , " AMD8111 " ) ;
if ( rtcs ) {
struct resource r ;
if ( of_address_to_resource ( rtcs , 0 , & r ) ) {
printk ( KERN_EMERG " Maple: Unable to translate NVRAM "
" address \n " ) ;
goto bail ;
}
if ( ! ( r . flags & IORESOURCE_IO ) ) {
printk ( KERN_EMERG " Maple: NVRAM address isn't PIO! \n " ) ;
goto bail ;
}
result = r . start ;
} else
printk ( KERN_EMERG " Maple: Unable to find NVRAM \n " ) ;
bail :
of_node_put ( rtcs ) ;
return result ;
}
2005-04-16 15:20:36 -07:00
static void maple_restart ( char * cmd )
{
2005-06-23 17:14:39 +10:00
unsigned int maple_nvram_base ;
2006-07-12 15:40:17 +10:00
const unsigned int * maple_nvram_offset , * maple_nvram_command ;
2006-01-14 16:35:35 +11:00
struct device_node * sp ;
2005-06-23 17:14:39 +10:00
2006-01-14 16:35:35 +11:00
maple_nvram_base = maple_find_nvram_base ( ) ;
if ( maple_nvram_base = = 0 )
goto fail ;
2005-06-23 17:14:39 +10:00
/* find service processor device */
2006-01-14 16:35:35 +11:00
sp = of_find_node_by_name ( NULL , " service-processor " ) ;
if ( ! sp ) {
2005-06-23 17:14:39 +10:00
printk ( KERN_EMERG " Maple: Unable to find Service Processor \n " ) ;
2006-01-14 16:35:35 +11:00
goto fail ;
2005-06-23 17:14:39 +10:00
}
2007-04-03 22:26:41 +10:00
maple_nvram_offset = of_get_property ( sp , " restart-addr " , NULL ) ;
maple_nvram_command = of_get_property ( sp , " restart-value " , NULL ) ;
2006-01-14 16:35:35 +11:00
of_node_put ( sp ) ;
2005-06-23 17:14:39 +10:00
/* send command */
2006-07-12 15:40:17 +10:00
outb_p ( * maple_nvram_command , maple_nvram_base + * maple_nvram_offset ) ;
2005-06-23 17:14:39 +10:00
for ( ; ; ) ;
2006-01-14 16:35:35 +11:00
fail :
printk ( KERN_EMERG " Maple: Manual Restart Required \n " ) ;
2005-04-16 15:20:36 -07:00
}
static void maple_power_off ( void )
{
2005-06-23 17:14:39 +10:00
unsigned int maple_nvram_base ;
2006-07-12 15:40:17 +10:00
const unsigned int * maple_nvram_offset , * maple_nvram_command ;
2006-01-14 16:35:35 +11:00
struct device_node * sp ;
2005-06-23 17:14:39 +10:00
2006-01-14 16:35:35 +11:00
maple_nvram_base = maple_find_nvram_base ( ) ;
if ( maple_nvram_base = = 0 )
goto fail ;
2005-06-23 17:14:39 +10:00
/* find service processor device */
2006-01-14 16:35:35 +11:00
sp = of_find_node_by_name ( NULL , " service-processor " ) ;
if ( ! sp ) {
2005-06-23 17:14:39 +10:00
printk ( KERN_EMERG " Maple: Unable to find Service Processor \n " ) ;
2006-01-14 16:35:35 +11:00
goto fail ;
2005-06-23 17:14:39 +10:00
}
2007-04-03 22:26:41 +10:00
maple_nvram_offset = of_get_property ( sp , " power-off-addr " , NULL ) ;
maple_nvram_command = of_get_property ( sp , " power-off-value " , NULL ) ;
2006-01-14 16:35:35 +11:00
of_node_put ( sp ) ;
2005-06-23 17:14:39 +10:00
/* send command */
2006-07-12 15:40:17 +10:00
outb_p ( * maple_nvram_command , maple_nvram_base + * maple_nvram_offset ) ;
2005-06-23 17:14:39 +10:00
for ( ; ; ) ;
2006-01-14 16:35:35 +11:00
fail :
printk ( KERN_EMERG " Maple: Manual Power-Down Required \n " ) ;
2005-04-16 15:20:36 -07:00
}
static void maple_halt ( void )
{
2005-06-23 17:14:39 +10:00
maple_power_off ( ) ;
2005-04-16 15:20:36 -07:00
}
# ifdef CONFIG_SMP
struct smp_ops_t maple_smp_ops = {
. probe = smp_mpic_probe ,
. message_pass = smp_mpic_message_pass ,
. kick_cpu = smp_generic_kick_cpu ,
. setup_cpu = smp_mpic_setup_cpu ,
. give_timebase = smp_generic_give_timebase ,
. take_timebase = smp_generic_take_timebase ,
} ;
# endif /* CONFIG_SMP */
2006-12-06 18:50:46 -06:00
static void __init maple_use_rtas_reboot_and_halt_if_present ( void )
{
if ( rtas_service_present ( " system-reboot " ) & &
rtas_service_present ( " power-off " ) ) {
ppc_md . restart = rtas_restart ;
ppc_md . power_off = rtas_power_off ;
ppc_md . halt = rtas_halt ;
}
}
2005-04-16 15:20:36 -07:00
void __init maple_setup_arch ( void )
{
/* init to some ~sane value until calibrate_delay() runs */
loops_per_jiffy = 50000000 ;
/* Setup SMP callback */
# ifdef CONFIG_SMP
smp_ops = & maple_smp_ops ;
# endif
/* Lookup PCI hosts */
maple_pci_init ( ) ;
# ifdef CONFIG_DUMMY_CONSOLE
conswitchp = & dummy_con ;
# endif
2006-12-06 18:50:46 -06:00
maple_use_rtas_reboot_and_halt_if_present ( ) ;
2005-07-07 17:56:30 -07:00
2006-04-12 15:23:22 -05:00
printk ( KERN_DEBUG " Using native/NAP idle loop \n " ) ;
2007-02-05 20:01:15 -06:00
mmio_nvram_init ( ) ;
2005-04-16 15:20:36 -07:00
}
/*
* Early initialization .
*/
static void __init maple_init_early ( void )
{
DBG ( " -> maple_init_early \n " ) ;
2005-12-14 13:10:10 +11:00
iommu_init_early_dart ( ) ;
2005-04-16 15:20:36 -07:00
DBG ( " <- maple_init_early \n " ) ;
}
2006-07-03 21:36:01 +10:00
/*
* This is almost identical to pSeries and CHRP . We need to make that
* code generic at one point , with appropriate bits in the device - tree to
* identify the presence of an HT APIC
*/
static void __init maple_init_IRQ ( void )
2005-04-16 15:20:36 -07:00
{
2006-07-03 21:36:01 +10:00
struct device_node * root , * np , * mpic_node = NULL ;
2006-07-12 15:40:17 +10:00
const unsigned int * opprop ;
2006-07-03 21:36:01 +10:00
unsigned long openpic_addr = 0 ;
int naddr , n , i , opplen , has_isus = 0 ;
2005-04-16 15:20:36 -07:00
struct mpic * mpic ;
2006-07-03 21:36:01 +10:00
unsigned int flags = MPIC_PRIMARY ;
2005-04-16 15:20:36 -07:00
2006-07-03 21:36:01 +10:00
/* Locate MPIC in the device-tree. Note that there is a bug
* in Maple device - tree where the type of the controller is
* open - pic and not interrupt - controller
*/
2006-07-08 02:37:20 +02:00
for_each_node_by_type ( np , " interrupt-controller " )
2007-05-03 17:26:52 +10:00
if ( of_device_is_compatible ( np , " open-pic " ) ) {
2006-07-08 02:37:20 +02:00
mpic_node = np ;
break ;
}
if ( mpic_node = = NULL )
for_each_node_by_type ( np , " open-pic " ) {
mpic_node = np ;
break ;
}
2006-07-03 21:36:01 +10:00
if ( mpic_node = = NULL ) {
printk ( KERN_ERR
" Failed to locate the MPIC interrupt controller \n " ) ;
return ;
}
2005-04-16 15:20:36 -07:00
2006-07-03 21:36:01 +10:00
/* Find address list in /platform-open-pic */
2005-04-16 15:20:36 -07:00
root = of_find_node_by_path ( " / " ) ;
2007-04-03 10:56:50 +10:00
naddr = of_n_addr_cells ( root ) ;
2007-04-03 22:26:41 +10:00
opprop = of_get_property ( root , " platform-open-pic " , & opplen ) ;
2006-07-03 21:36:01 +10:00
if ( opprop ! = 0 ) {
openpic_addr = of_read_number ( opprop , naddr ) ;
has_isus = ( opplen > naddr ) ;
printk ( KERN_DEBUG " OpenPIC addr: %lx, has ISUs: %d \n " ,
openpic_addr , has_isus ) ;
}
2005-04-16 15:20:36 -07:00
2006-07-03 21:36:01 +10:00
BUG_ON ( openpic_addr = = 0 ) ;
2005-04-16 15:20:36 -07:00
2006-07-03 21:36:01 +10:00
/* Check for a big endian MPIC */
2007-04-03 22:26:41 +10:00
if ( of_get_property ( np , " big-endian " , NULL ) ! = NULL )
2006-07-03 21:36:01 +10:00
flags | = MPIC_BIG_ENDIAN ;
/* XXX Maple specific bits */
2007-04-23 18:47:08 +10:00
flags | = MPIC_U3_HT_IRQS | MPIC_WANTS_RESET ;
2006-07-08 02:37:23 +02:00
/* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */
flags | = MPIC_BIG_ENDIAN ;
2006-07-03 21:36:01 +10:00
/* Setup the openpic driver. More device-tree junks, we hard code no
* ISUs for now . I ' ll have to revisit some stuffs with the folks doing
* the firmware for those
*/
mpic = mpic_alloc ( mpic_node , openpic_addr , flags ,
/*has_isus ? 16 :*/ 0 , 0 , " MPIC " ) ;
2005-04-16 15:20:36 -07:00
BUG_ON ( mpic = = NULL ) ;
2006-07-03 21:36:01 +10:00
/* Add ISUs */
opplen / = sizeof ( u32 ) ;
for ( n = 0 , i = naddr ; i < opplen ; i + = naddr , n + + ) {
unsigned long isuaddr = of_read_number ( opprop + i , naddr ) ;
mpic_assign_isu ( mpic , n , isuaddr ) ;
}
/* All ISUs are setup, complete initialization */
mpic_init ( mpic ) ;
ppc_md . get_irq = mpic_get_irq ;
of_node_put ( mpic_node ) ;
of_node_put ( root ) ;
2005-04-16 15:20:36 -07:00
}
static void __init maple_progress ( char * s , unsigned short hex )
{
printk ( " *** %04x : %s \n " , hex , s ? s : " " ) ;
}
/*
* Called very early , MMU is off , device - tree isn ' t unflattened
*/
2006-03-28 23:15:54 +11:00
static int __init maple_probe ( void )
2005-04-16 15:20:36 -07:00
{
2006-03-28 23:15:54 +11:00
unsigned long root = of_get_flat_dt_root ( ) ;
2006-07-03 17:22:05 +10:00
if ( ! of_flat_dt_is_compatible ( root , " Momentum,Maple " ) & &
! of_flat_dt_is_compatible ( root , " Momentum,Apache " ) )
2005-04-16 15:20:36 -07:00
return 0 ;
/*
* On U3 , the DART ( iommu ) must be allocated now since it
* has an impact on htab_initialize ( due to the large page it
* occupies having to be broken up so the DART itself is not
* part of the cacheable linar mapping
*/
2005-12-14 13:10:10 +11:00
alloc_dart_table ( ) ;
2005-04-16 15:20:36 -07:00
2006-06-23 18:16:38 +10:00
hpte_init_native ( ) ;
2005-04-16 15:20:36 -07:00
return 1 ;
}
2008-03-13 10:43:03 +11:00
define_machine ( maple ) {
2006-03-28 23:15:54 +11:00
. name = " Maple " ,
2005-04-16 15:20:36 -07:00
. probe = maple_probe ,
. setup_arch = maple_setup_arch ,
. init_early = maple_init_early ,
. init_IRQ = maple_init_IRQ ,
2006-11-11 17:24:51 +11:00
. pci_irq_fixup = maple_pci_irq_fixup ,
2005-04-16 15:20:36 -07:00
. pci_get_legacy_ide_irq = maple_pci_get_legacy_ide_irq ,
. restart = maple_restart ,
. power_off = maple_power_off ,
. halt = maple_halt ,
. get_boot_time = maple_get_boot_time ,
. set_rtc_time = maple_set_rtc_time ,
. get_rtc_time = maple_get_rtc_time ,
2005-06-23 09:43:07 +10:00
. calibrate_decr = generic_calibrate_decr ,
2005-04-16 15:20:36 -07:00
. progress = maple_progress ,
2006-03-27 15:03:03 +11:00
. power_save = power4_idle ,
2005-04-16 15:20:36 -07:00
} ;
2009-06-17 16:28:00 -07:00
# ifdef CONFIG_EDAC
/*
* Register a platform device for CPC925 memory controller on
* Motorola ATCA - 6101 blade .
*/
# define MAPLE_CPC925_MODEL "Motorola,ATCA-6101"
static int __init maple_cpc925_edac_setup ( void )
{
struct platform_device * pdev ;
struct device_node * np = NULL ;
struct resource r ;
const unsigned char * model ;
int ret ;
np = of_find_node_by_path ( " / " ) ;
if ( ! np ) {
printk ( KERN_ERR " %s: Unable to get root node \n " , __func__ ) ;
return - ENODEV ;
}
model = ( const unsigned char * ) of_get_property ( np , " model " , NULL ) ;
if ( ! model ) {
printk ( KERN_ERR " %s: Unabel to get model info \n " , __func__ ) ;
return - ENODEV ;
}
ret = strcmp ( model , MAPLE_CPC925_MODEL ) ;
of_node_put ( np ) ;
if ( ret ! = 0 )
return 0 ;
np = of_find_node_by_type ( NULL , " memory-controller " ) ;
if ( ! np ) {
printk ( KERN_ERR " %s: Unable to find memory-controller node \n " ,
__func__ ) ;
return - ENODEV ;
}
ret = of_address_to_resource ( np , 0 , & r ) ;
of_node_put ( np ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " %s: Unable to get memory-controller reg \n " ,
__func__ ) ;
return - ENODEV ;
}
pdev = platform_device_register_simple ( " cpc925_edac " , 0 , & r , 1 ) ;
if ( IS_ERR ( pdev ) )
return PTR_ERR ( pdev ) ;
printk ( KERN_INFO " %s: CPC925 platform device created \n " , __func__ ) ;
return 0 ;
}
machine_device_initcall ( maple , maple_cpc925_edac_setup ) ;
# endif