2009-08-17 00:13:29 +00:00
/*
* Copyright ( C ) 2009 Daniel Hellstrom ( daniel @ gaisler . com ) Aeroflex Gaisler AB
* Copyright ( C ) 2009 Konrad Eisele ( konrad @ gaisler . com ) Aeroflex Gaisler AB
*/
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/mutex.h>
# include <linux/of.h>
# include <linux/of_platform.h>
# include <linux/interrupt.h>
# include <linux/of_device.h>
2012-04-04 21:49:26 +02:00
# include <linux/clocksource.h>
# include <linux/clockchips.h>
2009-08-31 22:08:13 +00:00
2009-08-17 00:13:29 +00:00
# include <asm/oplib.h>
# include <asm/timer.h>
# include <asm/prom.h>
# include <asm/leon.h>
# include <asm/leon_amba.h>
2009-08-31 22:08:13 +00:00
# include <asm/traps.h>
# include <asm/cacheflush.h>
2011-04-19 23:41:22 +00:00
# include <asm/smp.h>
2011-04-21 04:20:24 +00:00
# include <asm/setup.h>
2009-08-17 00:13:29 +00:00
2012-05-25 21:20:12 +00:00
# include "kernel.h"
2009-08-17 00:13:29 +00:00
# include "prom.h"
# include "irq.h"
2011-01-04 01:41:29 +00:00
struct leon3_irqctrl_regs_map * leon3_irqctrl_regs ; /* interrupt controller base address */
struct leon3_gptimer_regs_map * leon3_gptimer_regs ; /* timer controller base address */
2009-08-17 00:13:29 +00:00
int leondebug_irq_disable ;
int leon_debug_irqout ;
2014-05-16 23:25:44 +02:00
static volatile u32 dummy_master_l10_counter ;
2011-01-27 01:26:58 +00:00
unsigned long amba_system_id ;
2011-04-19 23:41:21 +00:00
static DEFINE_SPINLOCK ( leon_irq_lock ) ;
2009-08-17 00:13:29 +00:00
2014-04-21 21:39:40 +02:00
static unsigned long leon3_gptimer_idx ; /* Timer Index (0..6) within Timer Core */
2014-08-29 17:09:18 +02:00
static unsigned long leon3_gptimer_ackmask ; /* For clearing pending bit */
2011-01-04 01:41:29 +00:00
unsigned long leon3_gptimer_irq ; /* interrupt controller irq number */
2009-08-17 00:13:29 +00:00
unsigned int sparc_leon_eirq ;
2011-04-19 23:41:25 +00:00
# define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu])
2011-04-19 23:41:22 +00:00
# define LEON_IACK (&leon3_irqctrl_regs->iclear)
# define LEON_DO_ACK_HW 1
2009-08-17 00:13:29 +00:00
2011-04-19 23:41:22 +00:00
/* Return the last ACKed IRQ by the Extended IRQ controller. It has already
* been ( automatically ) ACKed when the CPU takes the trap .
*/
static inline unsigned int leon_eirq_get ( int cpu )
2009-08-17 00:13:29 +00:00
{
return LEON3_BYPASS_LOAD_PA ( & leon3_irqctrl_regs - > intid [ cpu ] ) & 0x1f ;
}
2011-04-19 23:41:22 +00:00
/* Handle one or multiple IRQs from the extended interrupt controller */
2015-09-14 10:42:37 +02:00
static void leon_handle_ext_irq ( struct irq_desc * desc )
2009-08-17 00:13:29 +00:00
{
2011-04-19 23:41:22 +00:00
unsigned int eirq ;
2012-10-30 00:09:46 +00:00
struct irq_bucket * p ;
2011-04-21 04:20:24 +00:00
int cpu = sparc_leon3_cpuid ( ) ;
2011-04-19 23:41:22 +00:00
eirq = leon_eirq_get ( cpu ) ;
2012-10-30 00:09:46 +00:00
p = irq_map [ eirq ] ;
if ( ( eirq & 0x10 ) & & p & & p - > irq ) /* bit4 tells if IRQ happened */
generic_handle_irq ( p - > irq ) ;
2009-08-17 00:13:29 +00:00
}
/* The extended IRQ controller has been found, this function registers it */
2014-04-21 21:39:40 +02:00
static void leon_eirq_setup ( unsigned int eirq )
2009-08-17 00:13:29 +00:00
{
2011-04-19 23:41:22 +00:00
unsigned long mask , oldmask ;
unsigned int veirq ;
2009-08-17 00:13:29 +00:00
2011-04-19 23:41:22 +00:00
if ( eirq < 1 | | eirq > 0xf ) {
printk ( KERN_ERR " LEON EXT IRQ NUMBER BAD: %d \n " , eirq ) ;
return ;
2009-08-17 00:13:29 +00:00
}
2011-04-19 23:41:22 +00:00
veirq = leon_build_device_irq ( eirq , leon_handle_ext_irq , " extirq " , 0 ) ;
/*
* Unmask the Extended IRQ , the IRQs routed through the Ext - IRQ
* controller have a mask - bit of their own , so this is safe .
*/
irq_link ( veirq ) ;
mask = 1 < < eirq ;
2011-04-21 04:20:24 +00:00
oldmask = LEON3_BYPASS_LOAD_PA ( LEON_IMASK ( boot_cpu_id ) ) ;
LEON3_BYPASS_STORE_PA ( LEON_IMASK ( boot_cpu_id ) , ( oldmask | mask ) ) ;
2011-04-19 23:41:22 +00:00
sparc_leon_eirq = eirq ;
2009-08-17 00:13:29 +00:00
}
2012-05-14 15:14:36 +02:00
unsigned long leon_get_irqmask ( unsigned int irq )
2009-08-17 00:13:29 +00:00
{
unsigned long mask ;
if ( ! irq | | ( ( irq > 0xf ) & & ! sparc_leon_eirq )
| | ( ( irq > 0x1f ) & & sparc_leon_eirq ) ) {
printk ( KERN_ERR
" leon_get_irqmask: false irq number: %d \n " , irq ) ;
mask = 0 ;
} else {
mask = LEON_HARD_INT ( irq ) ;
}
return mask ;
}
2011-04-19 23:41:26 +00:00
# ifdef CONFIG_SMP
static int irq_choose_cpu ( const struct cpumask * affinity )
{
cpumask_t mask ;
2012-03-29 15:38:30 +10:30
cpumask_and ( & mask , cpu_online_mask , affinity ) ;
if ( cpumask_equal ( & mask , cpu_online_mask ) | | cpumask_empty ( & mask ) )
2011-04-21 04:20:24 +00:00
return boot_cpu_id ;
2011-04-19 23:41:26 +00:00
else
2012-03-29 15:38:30 +10:30
return cpumask_first ( & mask ) ;
2011-04-19 23:41:26 +00:00
}
# else
2011-04-21 04:20:24 +00:00
# define irq_choose_cpu(affinity) boot_cpu_id
2011-04-19 23:41:26 +00:00
# endif
static int leon_set_affinity ( struct irq_data * data , const struct cpumask * dest ,
bool force )
{
unsigned long mask , oldmask , flags ;
int oldcpu , newcpu ;
mask = ( unsigned long ) data - > chip_data ;
2015-06-01 16:05:35 +08:00
oldcpu = irq_choose_cpu ( irq_data_get_affinity_mask ( data ) ) ;
2011-04-19 23:41:26 +00:00
newcpu = irq_choose_cpu ( dest ) ;
if ( oldcpu = = newcpu )
goto out ;
/* unmask on old CPU first before enabling on the selected CPU */
spin_lock_irqsave ( & leon_irq_lock , flags ) ;
oldmask = LEON3_BYPASS_LOAD_PA ( LEON_IMASK ( oldcpu ) ) ;
LEON3_BYPASS_STORE_PA ( LEON_IMASK ( oldcpu ) , ( oldmask & ~ mask ) ) ;
oldmask = LEON3_BYPASS_LOAD_PA ( LEON_IMASK ( newcpu ) ) ;
LEON3_BYPASS_STORE_PA ( LEON_IMASK ( newcpu ) , ( oldmask | mask ) ) ;
spin_unlock_irqrestore ( & leon_irq_lock , flags ) ;
out :
return IRQ_SET_MASK_OK ;
}
2011-04-18 11:25:44 +00:00
static void leon_unmask_irq ( struct irq_data * data )
2009-08-17 00:13:29 +00:00
{
2011-04-19 23:41:25 +00:00
unsigned long mask , oldmask , flags ;
2011-04-19 23:41:26 +00:00
int cpu ;
2011-04-18 11:25:44 +00:00
mask = ( unsigned long ) data - > chip_data ;
2015-06-01 16:05:35 +08:00
cpu = irq_choose_cpu ( irq_data_get_affinity_mask ( data ) ) ;
2011-04-19 23:41:21 +00:00
spin_lock_irqsave ( & leon_irq_lock , flags ) ;
2011-04-19 23:41:26 +00:00
oldmask = LEON3_BYPASS_LOAD_PA ( LEON_IMASK ( cpu ) ) ;
LEON3_BYPASS_STORE_PA ( LEON_IMASK ( cpu ) , ( oldmask | mask ) ) ;
2011-04-19 23:41:21 +00:00
spin_unlock_irqrestore ( & leon_irq_lock , flags ) ;
2009-08-17 00:13:29 +00:00
}
2011-04-18 11:25:44 +00:00
static void leon_mask_irq ( struct irq_data * data )
2009-08-17 00:13:29 +00:00
{
2011-04-19 23:41:25 +00:00
unsigned long mask , oldmask , flags ;
2011-04-19 23:41:26 +00:00
int cpu ;
2011-04-18 11:25:44 +00:00
mask = ( unsigned long ) data - > chip_data ;
2015-06-01 16:05:35 +08:00
cpu = irq_choose_cpu ( irq_data_get_affinity_mask ( data ) ) ;
2011-04-19 23:41:21 +00:00
spin_lock_irqsave ( & leon_irq_lock , flags ) ;
2011-04-19 23:41:26 +00:00
oldmask = LEON3_BYPASS_LOAD_PA ( LEON_IMASK ( cpu ) ) ;
LEON3_BYPASS_STORE_PA ( LEON_IMASK ( cpu ) , ( oldmask & ~ mask ) ) ;
2011-04-19 23:41:21 +00:00
spin_unlock_irqrestore ( & leon_irq_lock , flags ) ;
2009-08-17 00:13:29 +00:00
}
2011-04-18 11:25:44 +00:00
static unsigned int leon_startup_irq ( struct irq_data * data )
{
irq_link ( data - > irq ) ;
leon_unmask_irq ( data ) ;
return 0 ;
}
static void leon_shutdown_irq ( struct irq_data * data )
{
leon_mask_irq ( data ) ;
irq_unlink ( data - > irq ) ;
}
2011-04-19 23:41:22 +00:00
/* Used by external level sensitive IRQ handlers on the LEON: ACK IRQ ctrl */
static void leon_eoi_irq ( struct irq_data * data )
{
unsigned long mask = ( unsigned long ) data - > chip_data ;
if ( mask & LEON_DO_ACK_HW )
LEON3_BYPASS_STORE_PA ( LEON_IACK , mask & ~ LEON_DO_ACK_HW ) ;
}
2011-04-18 11:25:44 +00:00
static struct irq_chip leon_irq = {
2011-04-19 23:41:26 +00:00
. name = " leon " ,
. irq_startup = leon_startup_irq ,
. irq_shutdown = leon_shutdown_irq ,
. irq_mask = leon_mask_irq ,
. irq_unmask = leon_unmask_irq ,
. irq_eoi = leon_eoi_irq ,
. irq_set_affinity = leon_set_affinity ,
2011-04-18 11:25:44 +00:00
} ;
2011-04-19 23:41:22 +00:00
/*
* Build a LEON IRQ for the edge triggered LEON IRQ controller :
* Edge ( normal ) IRQ - handle_simple_irq , ack = DONT - CARE , never ack
* Level IRQ ( PCI | Level - GPIO ) - handle_fasteoi_irq , ack = 1 , ack after ISR
* Per - CPU Edge - handle_percpu_irq , ack = 0
*/
unsigned int leon_build_device_irq ( unsigned int real_irq ,
irq_flow_handler_t flow_handler ,
const char * name , int do_ack )
2011-04-18 11:25:44 +00:00
{
unsigned int irq ;
unsigned long mask ;
2013-04-21 21:23:06 +00:00
struct irq_desc * desc ;
2011-04-18 11:25:44 +00:00
irq = 0 ;
2012-05-14 15:14:36 +02:00
mask = leon_get_irqmask ( real_irq ) ;
2011-04-18 11:25:44 +00:00
if ( mask = = 0 )
goto out ;
irq = irq_alloc ( real_irq , real_irq ) ;
if ( irq = = 0 )
goto out ;
2011-04-19 23:41:22 +00:00
if ( do_ack )
mask | = LEON_DO_ACK_HW ;
2013-04-21 21:23:06 +00:00
desc = irq_to_desc ( irq ) ;
if ( ! desc | | ! desc - > handle_irq | | desc - > handle_irq = = handle_bad_irq ) {
irq_set_chip_and_handler_name ( irq , & leon_irq ,
flow_handler , name ) ;
irq_set_chip_data ( irq , ( void * ) mask ) ;
}
2011-04-18 11:25:44 +00:00
out :
return irq ;
}
2011-04-19 23:41:22 +00:00
static unsigned int _leon_build_device_irq ( struct platform_device * op ,
unsigned int real_irq )
{
return leon_build_device_irq ( real_irq , handle_simple_irq , " edge " , 0 ) ;
}
2011-05-23 21:04:48 +00:00
void leon_update_virq_handling ( unsigned int virq ,
irq_flow_handler_t flow_handler ,
const char * name , int do_ack )
{
unsigned long mask = ( unsigned long ) irq_get_chip_data ( virq ) ;
mask & = ~ LEON_DO_ACK_HW ;
if ( do_ack )
mask | = LEON_DO_ACK_HW ;
irq_set_chip_and_handler_name ( virq , & leon_irq ,
flow_handler , name ) ;
irq_set_chip_data ( virq , ( void * ) mask ) ;
}
2012-04-04 21:49:26 +02:00
static u32 leon_cycles_offset ( void )
{
2014-08-29 17:09:18 +02:00
u32 rld , val , ctrl , off ;
2012-04-04 21:49:26 +02:00
rld = LEON3_BYPASS_LOAD_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . rld ) ;
val = LEON3_BYPASS_LOAD_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . val ) ;
2014-08-29 17:09:18 +02:00
ctrl = LEON3_BYPASS_LOAD_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . ctrl ) ;
if ( LEON3_GPTIMER_CTRL_ISPENDING ( ctrl ) ) {
val = LEON3_BYPASS_LOAD_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . val ) ;
off = 2 * rld - val ;
} else {
off = rld - val ;
}
return off ;
2012-04-04 21:49:26 +02:00
}
# ifdef CONFIG_SMP
/* smp clockevent irq */
2014-04-21 21:39:40 +02:00
static irqreturn_t leon_percpu_timer_ce_interrupt ( int irq , void * unused )
2012-04-04 21:49:26 +02:00
{
struct clock_event_device * ce ;
int cpu = smp_processor_id ( ) ;
leon_clear_profile_irq ( cpu ) ;
2013-06-10 08:53:28 +02:00
if ( cpu = = boot_cpu_id )
timer_interrupt ( irq , NULL ) ;
2012-04-04 21:49:26 +02:00
ce = & per_cpu ( sparc32_clockevent , cpu ) ;
irq_enter ( ) ;
if ( ce - > event_handler )
ce - > event_handler ( ce ) ;
irq_exit ( ) ;
return IRQ_HANDLED ;
}
# endif /* CONFIG_SMP */
void __init leon_init_timers ( void )
2009-08-17 00:13:29 +00:00
{
2011-04-19 23:41:22 +00:00
int irq , eirq ;
2011-01-04 01:41:32 +00:00
struct device_node * rootnp , * np , * nnp ;
2011-01-04 01:41:29 +00:00
struct property * pp ;
int len ;
2011-04-21 04:20:24 +00:00
int icsel ;
2011-01-04 01:41:32 +00:00
int ampopts ;
2011-04-18 11:25:44 +00:00
int err ;
2013-06-10 08:53:28 +02:00
u32 config ;
2014-08-29 17:09:18 +02:00
u32 ctrl ;
2009-08-17 00:13:29 +00:00
2012-04-04 21:49:26 +02:00
sparc_config . get_cycles_offset = leon_cycles_offset ;
sparc_config . cs_period = 1000000 / HZ ;
sparc_config . features | = FEAT_L10_CLOCKSOURCE ;
# ifndef CONFIG_SMP
sparc_config . features | = FEAT_L10_CLOCKEVENT ;
# endif
2009-08-17 00:13:29 +00:00
leondebug_irq_disable = 0 ;
leon_debug_irqout = 0 ;
2014-05-16 23:25:44 +02:00
master_l10_counter = ( u32 __iomem * ) & dummy_master_l10_counter ;
2009-08-17 00:13:29 +00:00
dummy_master_l10_counter = 0 ;
2011-01-04 01:41:29 +00:00
rootnp = of_find_node_by_path ( " /ambapp0 " ) ;
if ( ! rootnp )
goto bad ;
2011-01-27 01:26:58 +00:00
/* Find System ID: GRLIB build ID and optional CHIP ID */
pp = of_find_property ( rootnp , " systemid " , & len ) ;
if ( pp )
amba_system_id = * ( unsigned long * ) pp - > value ;
/* Find IRQMP IRQ Controller Registers base adr otherwise bail out */
2011-01-04 01:41:29 +00:00
np = of_find_node_by_name ( rootnp , " GAISLER_IRQMP " ) ;
2011-01-04 01:41:31 +00:00
if ( ! np ) {
np = of_find_node_by_name ( rootnp , " 01_00d " ) ;
if ( ! np )
goto bad ;
}
2011-01-04 01:41:29 +00:00
pp = of_find_property ( np , " reg " , & len ) ;
if ( ! pp )
goto bad ;
leon3_irqctrl_regs = * ( struct leon3_irqctrl_regs_map * * ) pp - > value ;
/* Find GPTIMER Timer Registers base address otherwise bail out. */
2011-01-04 01:41:32 +00:00
nnp = rootnp ;
do {
np = of_find_node_by_name ( nnp , " GAISLER_GPTIMER " ) ;
if ( ! np ) {
np = of_find_node_by_name ( nnp , " 01_011 " ) ;
if ( ! np )
goto bad ;
}
ampopts = 0 ;
pp = of_find_property ( np , " ampopts " , & len ) ;
if ( pp ) {
ampopts = * ( int * ) pp - > value ;
if ( ampopts = = 0 ) {
/* Skip this instance, resource already
* allocated by other OS */
nnp = np ;
continue ;
}
}
/* Select Timer-Instance on Timer Core. Default is zero */
leon3_gptimer_idx = ampopts & 0x7 ;
pp = of_find_property ( np , " reg " , & len ) ;
if ( pp )
leon3_gptimer_regs = * ( struct leon3_gptimer_regs_map * * )
pp - > value ;
pp = of_find_property ( np , " interrupts " , & len ) ;
if ( pp )
leon3_gptimer_irq = * ( unsigned int * ) pp - > value ;
} while ( 0 ) ;
2011-01-04 01:41:29 +00:00
2011-04-19 23:41:25 +00:00
if ( ! ( leon3_gptimer_regs & & leon3_irqctrl_regs & & leon3_gptimer_irq ) )
goto bad ;
2014-08-29 17:09:18 +02:00
ctrl = LEON3_BYPASS_LOAD_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . ctrl ) ;
LEON3_BYPASS_STORE_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . ctrl ,
ctrl | LEON3_GPTIMER_CTRL_PENDING ) ;
ctrl = LEON3_BYPASS_LOAD_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . ctrl ) ;
if ( ( ctrl & LEON3_GPTIMER_CTRL_PENDING ) ! = 0 )
leon3_gptimer_ackmask = ~ LEON3_GPTIMER_CTRL_PENDING ;
else
leon3_gptimer_ackmask = ~ 0 ;
2011-04-19 23:41:25 +00:00
LEON3_BYPASS_STORE_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . val , 0 ) ;
LEON3_BYPASS_STORE_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . rld ,
( ( ( 1000000 / HZ ) - 1 ) ) ) ;
LEON3_BYPASS_STORE_PA (
2011-01-04 01:41:32 +00:00
& leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . ctrl , 0 ) ;
2009-08-17 00:13:29 +00:00
2011-04-19 23:41:25 +00:00
/*
* The IRQ controller may ( if implemented ) consist of multiple
* IRQ controllers , each mapped on a 4 Kb boundary .
* Each CPU may be routed to different IRQCTRLs , however
* we assume that all CPUs ( in SMP system ) is routed to the
* same IRQ Controller , and for non - SMP only one IRQCTRL is
* accessed anyway .
* In AMP systems , Linux must run on CPU0 for the time being .
*/
2011-04-21 04:20:24 +00:00
icsel = LEON3_BYPASS_LOAD_PA ( & leon3_irqctrl_regs - > icsel [ boot_cpu_id / 8 ] ) ;
icsel = ( icsel > > ( ( 7 - ( boot_cpu_id & 0x7 ) ) * 4 ) ) & 0xf ;
2011-04-19 23:41:25 +00:00
leon3_irqctrl_regs + = icsel ;
2011-04-21 04:20:25 +00:00
/* Mask all IRQs on boot-cpu IRQ controller */
LEON3_BYPASS_STORE_PA ( & leon3_irqctrl_regs - > mask [ boot_cpu_id ] , 0 ) ;
2011-04-19 23:41:25 +00:00
/* Probe extended IRQ controller */
eirq = ( LEON3_BYPASS_LOAD_PA ( & leon3_irqctrl_regs - > mpstatus )
> > 16 ) & 0xf ;
if ( eirq ! = 0 )
leon_eirq_setup ( eirq ) ;
2011-06-09 02:54:09 +00:00
# ifdef CONFIG_SMP
{
unsigned long flags ;
/*
* In SMP , sun4m adds a IPI handler to IRQ trap handler that
* LEON never must take , sun4d and LEON overwrites the branch
* with a NOP .
*/
local_irq_save ( flags ) ;
patchme_maybe_smp_msg [ 0 ] = 0x01000000 ; /* NOP out the branch */
2012-05-13 20:49:31 -07:00
local_ops - > cache_all ( ) ;
2011-06-09 02:54:09 +00:00
local_irq_restore ( flags ) ;
}
# endif
2013-06-10 08:53:28 +02:00
config = LEON3_BYPASS_LOAD_PA ( & leon3_gptimer_regs - > config ) ;
if ( config & ( 1 < < LEON3_GPTIMER_SEPIRQ ) )
leon3_gptimer_irq + = leon3_gptimer_idx ;
else if ( ( config & LEON3_GPTIMER_TIMERS ) > 1 )
pr_warn ( " GPTIMER uses shared irqs, using other timers of the same core will fail. \n " ) ;
2009-08-31 22:08:13 +00:00
# ifdef CONFIG_SMP
2011-04-19 23:41:25 +00:00
/* Install per-cpu IRQ handler for broadcasted ticker */
2013-06-10 08:53:28 +02:00
irq = leon_build_device_irq ( leon3_gptimer_irq , handle_percpu_irq ,
2011-04-19 23:41:25 +00:00
" per-cpu " , 0 ) ;
2012-04-04 21:49:26 +02:00
err = request_irq ( irq , leon_percpu_timer_ce_interrupt ,
2013-06-10 08:53:28 +02:00
IRQF_PERCPU | IRQF_TIMER , " timer " , NULL ) ;
# else
irq = _leon_build_device_irq ( NULL , leon3_gptimer_irq ) ;
err = request_irq ( irq , timer_interrupt , IRQF_TIMER , " timer " , NULL ) ;
# endif
2011-04-19 23:41:25 +00:00
if ( err ) {
2013-06-10 08:53:28 +02:00
pr_err ( " Unable to attach timer IRQ%d \n " , irq ) ;
2011-04-19 23:41:25 +00:00
prom_halt ( ) ;
}
2013-06-10 08:53:28 +02:00
LEON3_BYPASS_STORE_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . ctrl ,
2011-04-19 23:41:25 +00:00
LEON3_GPTIMER_EN |
LEON3_GPTIMER_RL |
LEON3_GPTIMER_LD |
LEON3_GPTIMER_IRQEN ) ;
2011-01-04 01:41:29 +00:00
return ;
bad :
printk ( KERN_ERR " No Timer/irqctrl found \n " ) ;
BUG ( ) ;
return ;
2009-08-17 00:13:29 +00:00
}
2012-05-14 17:30:35 +02:00
static void leon_clear_clock_irq ( void )
2009-08-17 00:13:29 +00:00
{
2014-08-29 17:09:18 +02:00
u32 ctrl ;
ctrl = LEON3_BYPASS_LOAD_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . ctrl ) ;
LEON3_BYPASS_STORE_PA ( & leon3_gptimer_regs - > e [ leon3_gptimer_idx ] . ctrl ,
ctrl & leon3_gptimer_ackmask ) ;
2009-08-17 00:13:29 +00:00
}
2012-05-14 17:30:35 +02:00
static void leon_load_profile_irq ( int cpu , unsigned int limit )
2009-08-17 00:13:29 +00:00
{
}
void __init leon_trans_init ( struct device_node * dp )
{
if ( strcmp ( dp - > type , " cpu " ) = = 0 & & strcmp ( dp - > name , " <NULL> " ) = = 0 ) {
struct property * p ;
p = of_find_property ( dp , " mid " , ( void * ) 0 ) ;
if ( p ) {
int mid ;
dp - > name = prom_early_alloc ( 5 + 1 ) ;
memcpy ( & mid , p - > value , p - > length ) ;
sprintf ( ( char * ) dp - > name , " cpu%.2d " , mid ) ;
}
}
}
2009-08-31 22:08:13 +00:00
# ifdef CONFIG_SMP
void leon_clear_profile_irq ( int cpu )
{
}
void leon_enable_irq_cpu ( unsigned int irq_nr , unsigned int cpu )
{
unsigned long mask , flags , * addr ;
2012-05-14 15:14:36 +02:00
mask = leon_get_irqmask ( irq_nr ) ;
2011-04-19 23:41:21 +00:00
spin_lock_irqsave ( & leon_irq_lock , flags ) ;
2011-04-19 23:41:25 +00:00
addr = ( unsigned long * ) LEON_IMASK ( cpu ) ;
LEON3_BYPASS_STORE_PA ( addr , ( LEON3_BYPASS_LOAD_PA ( addr ) | mask ) ) ;
2011-04-19 23:41:21 +00:00
spin_unlock_irqrestore ( & leon_irq_lock , flags ) ;
2009-08-31 22:08:13 +00:00
}
# endif
2009-08-17 00:13:29 +00:00
void __init leon_init_IRQ ( void )
{
2012-04-04 13:21:13 +02:00
sparc_config . init_timers = leon_init_timers ;
sparc_config . build_device_irq = _leon_build_device_irq ;
2012-05-14 17:30:35 +02:00
sparc_config . clock_rate = 1000000 ;
sparc_config . clear_clock_irq = leon_clear_clock_irq ;
sparc_config . load_profile_irq = leon_load_profile_irq ;
2009-08-17 00:13:29 +00:00
}