2006-09-06 14:42:08 -05:00
/*
2007-02-04 16:36:55 -06:00
* Copyright ( C ) 2006 - 2007 PA Semi , Inc
2006-09-06 14:42:08 -05:00
*
* Authors : Kip Walker , PA Semi
* Olof Johansson , PA Semi
*
* Maintained by : Olof Johansson < olof @ lixom . net >
*
* Based on arch / powerpc / platforms / maple / setup . c
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/delay.h>
# include <linux/console.h>
2006-11-11 17:25:02 +11:00
# include <linux/pci.h>
2006-09-06 14:42:08 -05:00
# include <asm/prom.h>
# include <asm/system.h>
# include <asm/iommu.h>
# include <asm/machdep.h>
# include <asm/mpic.h>
# include <asm/smp.h>
# include <asm/time.h>
2007-04-25 04:01:34 +10:00
# include <asm/of_platform.h>
2006-09-06 14:42:08 -05:00
# include "pasemi.h"
2007-02-04 16:36:52 -06:00
static void __iomem * reset_reg ;
2006-09-06 14:42:08 -05:00
2007-02-04 16:36:52 -06:00
static void pas_restart ( char * cmd )
2006-09-06 14:42:08 -05:00
{
2007-02-04 16:36:52 -06:00
printk ( " Restarting... \n " ) ;
while ( 1 )
out_le32 ( reset_reg , 0x6000000 ) ;
2006-09-06 14:42:08 -05:00
}
# ifdef CONFIG_SMP
2007-02-04 16:36:53 -06:00
static DEFINE_SPINLOCK ( timebase_lock ) ;
static void __devinit pas_give_timebase ( void )
{
unsigned long tb ;
spin_lock ( & timebase_lock ) ;
mtspr ( SPRN_TBCTL , TBCTL_FREEZE ) ;
tb = mftb ( ) ;
mtspr ( SPRN_TBCTL , TBCTL_UPDATE_LOWER | ( tb & 0xffffffff ) ) ;
mtspr ( SPRN_TBCTL , TBCTL_UPDATE_UPPER | ( tb > > 32 ) ) ;
mtspr ( SPRN_TBCTL , TBCTL_RESTART ) ;
spin_unlock ( & timebase_lock ) ;
pr_debug ( " pas_give_timebase: cpu %d gave tb %lx \n " ,
smp_processor_id ( ) , tb ) ;
}
static void __devinit pas_take_timebase ( void )
{
pr_debug ( " pas_take_timebase: cpu %d has tb %lx \n " ,
smp_processor_id ( ) , mftb ( ) ) ;
}
2006-09-06 14:42:08 -05:00
struct smp_ops_t pas_smp_ops = {
. probe = smp_mpic_probe ,
. message_pass = smp_mpic_message_pass ,
. kick_cpu = smp_generic_kick_cpu ,
. setup_cpu = smp_mpic_setup_cpu ,
2007-02-04 16:36:53 -06:00
. give_timebase = pas_give_timebase ,
. take_timebase = pas_take_timebase ,
2006-09-06 14:42:08 -05:00
} ;
# endif /* CONFIG_SMP */
void __init pas_setup_arch ( void )
{
# ifdef CONFIG_SMP
/* Setup SMP callback */
smp_ops = & pas_smp_ops ;
# endif
/* Lookup PCI hosts */
pas_pci_init ( ) ;
# ifdef CONFIG_DUMMY_CONSOLE
conswitchp = & dummy_con ;
# endif
2007-02-04 16:36:52 -06:00
/* Remap SDC register for doing reset */
/* XXXOJN This should maybe come out of the device tree */
reset_reg = ioremap ( 0xfc101100 , 4 ) ;
2007-02-04 16:36:51 -06:00
pasemi_idle_init ( ) ;
2006-09-06 14:42:08 -05:00
}
static __init void pas_init_IRQ ( void )
{
struct device_node * np ;
struct device_node * root , * mpic_node ;
unsigned long openpic_addr ;
const unsigned int * opprop ;
int naddr , opplen ;
struct mpic * mpic ;
mpic_node = NULL ;
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-09-06 14:42:08 -05:00
mpic_node = np ;
break ;
}
if ( ! mpic_node )
for_each_node_by_type ( np , " open-pic " ) {
mpic_node = np ;
break ;
}
if ( ! mpic_node ) {
printk ( KERN_ERR
" Failed to locate the MPIC interrupt controller \n " ) ;
return ;
}
/* Find address list in /platform-open-pic */
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-09-06 14:42:08 -05:00
if ( ! opprop ) {
printk ( KERN_ERR " No platform-open-pic property. \n " ) ;
of_node_put ( root ) ;
return ;
}
openpic_addr = of_read_number ( opprop , naddr ) ;
printk ( KERN_DEBUG " OpenPIC addr: %lx \n " , openpic_addr ) ;
2007-01-28 23:33:18 -06:00
mpic = mpic_alloc ( mpic_node , openpic_addr ,
2007-04-16 16:28:38 +10:00
MPIC_PRIMARY | MPIC_LARGE_VECTORS | MPIC_WANTS_RESET ,
2007-01-28 23:33:18 -06:00
0 , 0 , " PAS-OPIC " ) ;
2006-09-06 14:42:08 -05:00
BUG_ON ( ! mpic ) ;
mpic_assign_isu ( mpic , 0 , openpic_addr + 0x10000 ) ;
mpic_init ( mpic ) ;
of_node_put ( mpic_node ) ;
of_node_put ( root ) ;
}
static void __init pas_progress ( char * s , unsigned short hex )
{
printk ( " [%04x] : %s \n " , hex , s ? s : " " ) ;
}
2007-02-04 16:36:50 -06:00
static int pas_machine_check_handler ( struct pt_regs * regs )
{
int cpu = smp_processor_id ( ) ;
unsigned long srr0 , srr1 , dsisr ;
srr0 = regs - > nip ;
srr1 = regs - > msr ;
dsisr = mfspr ( SPRN_DSISR ) ;
printk ( KERN_ERR " Machine Check on CPU %d \n " , cpu ) ;
printk ( KERN_ERR " SRR0 0x%016lx SRR1 0x%016lx \n " , srr0 , srr1 ) ;
printk ( KERN_ERR " DSISR 0x%016lx DAR 0x%016lx \n " , dsisr , regs - > dar ) ;
printk ( KERN_ERR " Cause: \n " ) ;
if ( srr1 & 0x200000 )
printk ( KERN_ERR " Signalled by SDC \n " ) ;
if ( srr1 & 0x100000 ) {
printk ( KERN_ERR " Load/Store detected error: \n " ) ;
if ( dsisr & 0x8000 )
printk ( KERN_ERR " D-cache ECC double-bit error or bus error \n " ) ;
if ( dsisr & 0x4000 )
printk ( KERN_ERR " LSU snoop response error \n " ) ;
if ( dsisr & 0x2000 )
printk ( KERN_ERR " MMU SLB multi-hit or invalid B field \n " ) ;
if ( dsisr & 0x1000 )
printk ( KERN_ERR " Recoverable Duptags \n " ) ;
if ( dsisr & 0x800 )
printk ( KERN_ERR " Recoverable D-cache parity error count overflow \n " ) ;
if ( dsisr & 0x400 )
printk ( KERN_ERR " TLB parity error count overflow \n " ) ;
}
if ( srr1 & 0x80000 )
printk ( KERN_ERR " Bus Error \n " ) ;
if ( srr1 & 0x40000 )
printk ( KERN_ERR " I-side SLB multiple hit \n " ) ;
if ( srr1 & 0x20000 )
printk ( KERN_ERR " I-cache parity error hit \n " ) ;
/* SRR1[62] is from MSR[62] if recoverable, so pass that back */
return ! ! ( srr1 & 0x2 ) ;
}
2007-02-04 16:36:55 -06:00
static void __init pas_init_early ( void )
{
iommu_init_early_pasemi ( ) ;
}
2007-04-18 16:39:54 +10:00
static struct of_device_id pasemi_bus_ids [ ] = {
{ . type = " sdc " , } ,
{ } ,
} ;
static int __init pasemi_publish_devices ( void )
{
2007-05-01 14:43:39 +10:00
if ( ! machine_is ( pasemi ) )
return 0 ;
/* Publish OF platform devices for SDC and other non-PCI devices */
2007-04-18 16:39:54 +10:00
of_platform_bus_probe ( NULL , pasemi_bus_ids , NULL ) ;
return 0 ;
}
device_initcall ( pasemi_publish_devices ) ;
2007-02-04 16:36:50 -06:00
2006-09-06 14:42:08 -05:00
/*
* Called very early , MMU is off , device - tree isn ' t unflattened
*/
static int __init pas_probe ( void )
{
unsigned long root = of_get_flat_dt_root ( ) ;
if ( ! of_flat_dt_is_compatible ( root , " PA6T-1682M " ) )
return 0 ;
hpte_init_native ( ) ;
2007-02-04 16:36:55 -06:00
alloc_iobmap_l2 ( ) ;
2006-09-06 14:42:08 -05:00
return 1 ;
}
define_machine ( pas ) {
. name = " PA Semi PA6T-1682M " ,
. probe = pas_probe ,
. setup_arch = pas_setup_arch ,
2007-02-04 16:36:55 -06:00
. init_early = pas_init_early ,
2006-09-06 14:42:08 -05:00
. init_IRQ = pas_init_IRQ ,
. get_irq = mpic_get_irq ,
. restart = pas_restart ,
. get_boot_time = pas_get_boot_time ,
. calibrate_decr = generic_calibrate_decr ,
. progress = pas_progress ,
2007-02-04 16:36:50 -06:00
. machine_check_exception = pas_machine_check_handler ,
2007-02-04 16:36:54 -06:00
. pci_irq_fixup = pas_pci_irq_fixup ,
2006-09-06 14:42:08 -05:00
} ;