2011-02-22 21:07:37 +01:00
/*
* Architecture specific OF callbacks .
*/
# include <linux/bootmem.h>
# include <linux/io.h>
2011-02-22 21:07:39 +01:00
# include <linux/interrupt.h>
2011-02-22 21:07:37 +01:00
# include <linux/list.h>
# include <linux/of.h>
# include <linux/of_fdt.h>
2011-02-22 21:07:40 +01:00
# include <linux/of_address.h>
2011-02-22 21:07:37 +01:00
# include <linux/of_platform.h>
# include <linux/slab.h>
2011-02-22 21:07:41 +01:00
# include <asm/hpet.h>
2011-02-22 21:07:39 +01:00
# include <asm/irq_controller.h>
2011-02-22 21:07:40 +01:00
# include <asm/apic.h>
2011-02-22 21:07:39 +01:00
2011-02-22 21:07:40 +01:00
__initdata u64 initial_dtb ;
2011-02-22 21:07:37 +01:00
char __initdata cmd_line [ COMMAND_LINE_SIZE ] ;
2011-02-22 21:07:39 +01:00
static LIST_HEAD ( irq_domains ) ;
static DEFINE_RAW_SPINLOCK ( big_irq_lock ) ;
2011-02-22 21:07:40 +01:00
int __initdata of_ioapic ;
2011-02-22 21:07:39 +01:00
void add_interrupt_host ( struct irq_domain * ih )
{
unsigned long flags ;
raw_spin_lock_irqsave ( & big_irq_lock , flags ) ;
list_add ( & ih - > l , & irq_domains ) ;
raw_spin_unlock_irqrestore ( & big_irq_lock , flags ) ;
}
static struct irq_domain * get_ih_from_node ( struct device_node * controller )
{
struct irq_domain * ih , * found = NULL ;
unsigned long flags ;
raw_spin_lock_irqsave ( & big_irq_lock , flags ) ;
list_for_each_entry ( ih , & irq_domains , l ) {
if ( ih - > controller = = controller ) {
found = ih ;
break ;
}
}
raw_spin_unlock_irqrestore ( & big_irq_lock , flags ) ;
return found ;
}
2011-02-22 21:07:37 +01:00
unsigned int irq_create_of_mapping ( struct device_node * controller ,
const u32 * intspec , unsigned int intsize )
{
2011-02-22 21:07:39 +01:00
struct irq_domain * ih ;
u32 virq , type ;
int ret ;
2011-02-22 21:07:37 +01:00
2011-02-22 21:07:39 +01:00
ih = get_ih_from_node ( controller ) ;
if ( ! ih )
return 0 ;
ret = ih - > xlate ( ih , intspec , intsize , & virq , & type ) ;
if ( ret )
return ret ;
if ( type = = IRQ_TYPE_NONE )
return virq ;
/* set the mask if it is different from current */
if ( type = = ( irq_to_desc ( virq ) - > status & IRQF_TRIGGER_MASK ) )
set_irq_type ( virq , type ) ;
return virq ;
2011-02-22 21:07:37 +01:00
}
EXPORT_SYMBOL_GPL ( irq_create_of_mapping ) ;
unsigned long pci_address_to_pio ( phys_addr_t address )
{
/*
* The ioport address can be directly used by inX / outX
*/
BUG_ON ( address > = ( 1 < < 16 ) ) ;
return ( unsigned long ) address ;
}
EXPORT_SYMBOL_GPL ( pci_address_to_pio ) ;
void __init early_init_dt_scan_chosen_arch ( unsigned long node )
{
BUG ( ) ;
}
void __init early_init_dt_add_memory_arch ( u64 base , u64 size )
{
BUG ( ) ;
}
void * __init early_init_dt_alloc_memory_arch ( u64 size , u64 align )
{
return __alloc_bootmem ( size , align , __pa ( MAX_DMA_ADDRESS ) ) ;
}
void __init add_dtb ( u64 data )
{
2011-02-22 21:07:40 +01:00
initial_dtb = data + offsetof ( struct setup_data , data ) ;
}
2011-02-22 21:07:41 +01:00
static void __init dtb_setup_hpet ( void )
{
struct device_node * dn ;
struct resource r ;
int ret ;
dn = of_find_compatible_node ( NULL , NULL , " intel,ce4100-hpet " ) ;
if ( ! dn )
return ;
ret = of_address_to_resource ( dn , 0 , & r ) ;
if ( ret ) {
WARN_ON ( 1 ) ;
return ;
}
hpet_address = r . start ;
}
2011-02-22 21:07:40 +01:00
static void __init dtb_lapic_setup ( void )
{
# ifdef CONFIG_X86_LOCAL_APIC
if ( apic_force_enable ( ) )
return ;
smp_found_config = 1 ;
pic_mode = 1 ;
/* Required for ioapic registration */
set_fixmap_nocache ( FIX_APIC_BASE , mp_lapic_addr ) ;
if ( boot_cpu_physical_apicid = = - 1U )
boot_cpu_physical_apicid = read_apic_id ( ) ;
generic_processor_info ( boot_cpu_physical_apicid ,
GET_APIC_VERSION ( apic_read ( APIC_LVR ) ) ) ;
# endif
}
# ifdef CONFIG_X86_IO_APIC
static unsigned int ioapic_id ;
static void __init dtb_add_ioapic ( struct device_node * dn )
{
struct resource r ;
int ret ;
ret = of_address_to_resource ( dn , 0 , & r ) ;
if ( ret ) {
printk ( KERN_ERR " Can't obtain address from node %s. \n " ,
dn - > full_name ) ;
return ;
}
mp_register_ioapic ( + + ioapic_id , r . start , gsi_top ) ;
}
static void __init dtb_ioapic_setup ( void )
{
struct device_node * dn ;
if ( ! smp_found_config )
return ;
for_each_compatible_node ( dn , NULL , " intel,ce4100-ioapic " )
dtb_add_ioapic ( dn ) ;
if ( nr_ioapics ) {
of_ioapic = 1 ;
return ;
}
printk ( KERN_ERR " Error: No information about IO-APIC in OF. \n " ) ;
smp_found_config = 0 ;
}
# else
static void __init dtb_ioapic_setup ( void ) { }
# endif
static void __init dtb_apic_setup ( void )
{
dtb_lapic_setup ( ) ;
dtb_ioapic_setup ( ) ;
}
void __init x86_dtb_find_config ( void )
{
if ( initial_dtb )
smp_found_config = 1 ;
else
printk ( KERN_ERR " Missing device tree!. \n " ) ;
}
void __init x86_dtb_get_config ( unsigned int unused )
{
u32 size , map_len ;
void * new_dtb ;
if ( ! initial_dtb )
return ;
map_len = max ( PAGE_SIZE - ( initial_dtb & ~ PAGE_MASK ) ,
( u64 ) sizeof ( struct boot_param_header ) ) ;
initial_boot_params = early_memremap ( initial_dtb , map_len ) ;
size = be32_to_cpu ( initial_boot_params - > totalsize ) ;
if ( map_len < size ) {
early_iounmap ( initial_boot_params , map_len ) ;
initial_boot_params = early_memremap ( initial_dtb , size ) ;
map_len = size ;
}
new_dtb = alloc_bootmem ( size ) ;
memcpy ( new_dtb , initial_boot_params , size ) ;
early_iounmap ( initial_boot_params , map_len ) ;
initial_boot_params = new_dtb ;
/* root level address cells */
of_scan_flat_dt ( early_init_dt_scan_root , NULL ) ;
unflatten_device_tree ( ) ;
2011-02-22 21:07:41 +01:00
dtb_setup_hpet ( ) ;
2011-02-22 21:07:40 +01:00
dtb_apic_setup ( ) ;
2011-02-22 21:07:37 +01:00
}