-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ARCv2: [intc] HS38 core interrupt controller
Cc: Jason Cooper <jason@lakedaemon.net> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
- Loading branch information
Vineet Gupta
committed
Jun 22, 2015
1 parent
10d11e5
commit 820970a
Showing
4 changed files
with
282 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
* ARC-HS incore Interrupt Controller (Provided by cores implementing ARCv2 ISA) | ||
|
||
Properties: | ||
|
||
- compatible: "snps,archs-intc" | ||
- interrupt-controller: This is an interrupt controller. | ||
- #interrupt-cells: Must be <1>. | ||
|
||
Single Cell "interrupts" property of a device specifies the IRQ number | ||
between 16 to 256 | ||
|
||
intc accessed via the special ARC AUX register interface, hence "reg" property | ||
is not specified. | ||
|
||
Example: | ||
|
||
intc: interrupt-controller { | ||
compatible = "snps,archs-intc"; | ||
interrupt-controller; | ||
#interrupt-cells = <1>; | ||
interrupts = <16 17 18 19 20 21 22 23 24 25>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* | ||
* Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com) | ||
* | ||
* 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. | ||
*/ | ||
|
||
#ifndef __ASM_IRQFLAGS_ARCV2_H | ||
#define __ASM_IRQFLAGS_ARCV2_H | ||
|
||
#include <asm/arcregs.h> | ||
|
||
/* status32 Bits */ | ||
#define STATUS_AD_BIT 19 /* Disable Align chk: core supports non-aligned */ | ||
#define STATUS_IE_BIT 31 | ||
|
||
#define STATUS_AD_MASK (1<<STATUS_AD_BIT) | ||
#define STATUS_IE_MASK (1<<STATUS_IE_BIT) | ||
|
||
#define AUX_USER_SP 0x00D | ||
#define AUX_IRQ_CTRL 0x00E | ||
#define AUX_IRQ_ACT 0x043 /* Active Intr across all levels */ | ||
#define AUX_IRQ_LVL_PEND 0x200 /* Pending Intr across all levels */ | ||
#define AUX_IRQ_PRIORITY 0x206 | ||
#define ICAUSE 0x40a | ||
#define AUX_IRQ_SELECT 0x40b | ||
#define AUX_IRQ_ENABLE 0x40c | ||
|
||
/* 0 is highest level, but taken by FIRQs, if present in design */ | ||
#define ARCV2_IRQ_DEF_PRIO 0 | ||
|
||
/* seed value for status register */ | ||
#define ISA_INIT_STATUS_BITS (STATUS_IE_MASK | STATUS_AD_MASK | \ | ||
(ARCV2_IRQ_DEF_PRIO << 1)) | ||
|
||
#ifndef __ASSEMBLY__ | ||
|
||
/* | ||
* Save IRQ state and disable IRQs | ||
*/ | ||
static inline long arch_local_irq_save(void) | ||
{ | ||
unsigned long flags; | ||
|
||
__asm__ __volatile__(" clri %0 \n" : "=r" (flags) : : "memory"); | ||
|
||
return flags; | ||
} | ||
|
||
/* | ||
* restore saved IRQ state | ||
*/ | ||
static inline void arch_local_irq_restore(unsigned long flags) | ||
{ | ||
__asm__ __volatile__(" seti %0 \n" : : "r" (flags) : "memory"); | ||
} | ||
|
||
/* | ||
* Unconditionally Enable IRQs | ||
*/ | ||
static inline void arch_local_irq_enable(void) | ||
{ | ||
__asm__ __volatile__(" seti \n" : : : "memory"); | ||
} | ||
|
||
/* | ||
* Unconditionally Disable IRQs | ||
*/ | ||
static inline void arch_local_irq_disable(void) | ||
{ | ||
__asm__ __volatile__(" clri \n" : : : "memory"); | ||
} | ||
|
||
/* | ||
* save IRQ state | ||
*/ | ||
static inline long arch_local_save_flags(void) | ||
{ | ||
unsigned long temp; | ||
|
||
__asm__ __volatile__( | ||
" lr %0, [status32] \n" | ||
: "=&r"(temp) | ||
: | ||
: "memory"); | ||
|
||
return temp; | ||
} | ||
|
||
/* | ||
* Query IRQ state | ||
*/ | ||
static inline int arch_irqs_disabled_flags(unsigned long flags) | ||
{ | ||
return !(flags & (STATUS_IE_MASK)); | ||
} | ||
|
||
static inline int arch_irqs_disabled(void) | ||
{ | ||
return arch_irqs_disabled_flags(arch_local_save_flags()); | ||
} | ||
|
||
#else | ||
|
||
.macro IRQ_DISABLE scratch | ||
clri | ||
.endm | ||
|
||
.macro IRQ_ENABLE scratch | ||
seti | ||
.endm | ||
|
||
#endif /* __ASSEMBLY__ */ | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/* | ||
* Copyright (C) 2014 Synopsys, Inc. (www.synopsys.com) | ||
* | ||
* 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. | ||
* | ||
*/ | ||
|
||
#include <linux/interrupt.h> | ||
#include <linux/module.h> | ||
#include <linux/of.h> | ||
#include <linux/irqdomain.h> | ||
#include <linux/irqchip.h> | ||
#include "../../drivers/irqchip/irqchip.h" | ||
#include <asm/irq.h> | ||
|
||
/* | ||
* Early Hardware specific Interrupt setup | ||
* -Called very early (start_kernel -> setup_arch -> setup_processor) | ||
* -Platform Independent (must for any ARC Core) | ||
* -Needed for each CPU (hence not foldable into init_IRQ) | ||
*/ | ||
void arc_init_IRQ(void) | ||
{ | ||
unsigned int tmp; | ||
|
||
struct aux_irq_ctrl { | ||
#ifdef CONFIG_CPU_BIG_ENDIAN | ||
unsigned int res3:18, save_idx_regs:1, res2:1, | ||
save_u_to_u:1, save_lp_regs:1, save_blink:1, | ||
res:4, save_nr_gpr_pairs:5; | ||
#else | ||
unsigned int save_nr_gpr_pairs:5, res:4, | ||
save_blink:1, save_lp_regs:1, save_u_to_u:1, | ||
res2:1, save_idx_regs:1, res3:18; | ||
#endif | ||
} ictrl; | ||
|
||
*(unsigned int *)&ictrl = 0; | ||
|
||
ictrl.save_nr_gpr_pairs = 6; /* r0 to r11 (r12 saved manually) */ | ||
ictrl.save_blink = 1; | ||
ictrl.save_lp_regs = 1; /* LP_COUNT, LP_START, LP_END */ | ||
ictrl.save_u_to_u = 0; /* user ctxt saved on kernel stack */ | ||
ictrl.save_idx_regs = 1; /* JLI, LDI, EI */ | ||
|
||
WRITE_AUX(AUX_IRQ_CTRL, ictrl); | ||
|
||
/* setup status32, don't enable intr yet as kernel doesn't want */ | ||
tmp = read_aux_reg(0xa); | ||
tmp |= ISA_INIT_STATUS_BITS; | ||
tmp &= ~STATUS_IE_MASK; | ||
asm volatile("flag %0 \n"::"r"(tmp)); | ||
|
||
/* | ||
* ARCv2 core intc provides multiple interrupt priorities (upto 16). | ||
* Typical builds though have only two levels (0-high, 1-low) | ||
* Linux by default uses lower prio 1 for most irqs, reserving 0 for | ||
* NMI style interrupts in future (say perf) | ||
* | ||
* Read the intc BCR to confirm that Linux default priority is avail | ||
* in h/w | ||
* | ||
* Note: | ||
* IRQ_BCR[27..24] contains N-1 (for N priority levels) and prio level | ||
* is 0 based. | ||
*/ | ||
tmp = (read_aux_reg(ARC_REG_IRQ_BCR) >> 24 ) & 0xF; | ||
if (ARCV2_IRQ_DEF_PRIO > tmp) | ||
panic("Linux default irq prio incorrect\n"); | ||
} | ||
|
||
static void arcv2_irq_mask(struct irq_data *data) | ||
{ | ||
write_aux_reg(AUX_IRQ_SELECT, data->irq); | ||
write_aux_reg(AUX_IRQ_ENABLE, 0); | ||
} | ||
|
||
static void arcv2_irq_unmask(struct irq_data *data) | ||
{ | ||
write_aux_reg(AUX_IRQ_SELECT, data->irq); | ||
write_aux_reg(AUX_IRQ_ENABLE, 1); | ||
} | ||
|
||
void arcv2_irq_enable(struct irq_data *data) | ||
{ | ||
/* set default priority */ | ||
write_aux_reg(AUX_IRQ_SELECT, data->irq); | ||
write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO); | ||
|
||
/* | ||
* hw auto enables (linux unmask) all by default | ||
* So no need to do IRQ_ENABLE here | ||
* XXX: However OSCI LAN need it | ||
*/ | ||
write_aux_reg(AUX_IRQ_ENABLE, 1); | ||
} | ||
|
||
static struct irq_chip arcv2_irq_chip = { | ||
.name = "ARCv2 core Intc", | ||
.irq_mask = arcv2_irq_mask, | ||
.irq_unmask = arcv2_irq_unmask, | ||
.irq_enable = arcv2_irq_enable | ||
}; | ||
|
||
static int arcv2_irq_map(struct irq_domain *d, unsigned int irq, | ||
irq_hw_number_t hw) | ||
{ | ||
if (irq == TIMER0_IRQ) | ||
irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_percpu_irq); | ||
else | ||
irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_level_irq); | ||
|
||
return 0; | ||
} | ||
|
||
static const struct irq_domain_ops arcv2_irq_ops = { | ||
.xlate = irq_domain_xlate_onecell, | ||
.map = arcv2_irq_map, | ||
}; | ||
|
||
static struct irq_domain *root_domain; | ||
|
||
static int __init | ||
init_onchip_IRQ(struct device_node *intc, struct device_node *parent) | ||
{ | ||
if (parent) | ||
panic("DeviceTree incore intc not a root irq controller\n"); | ||
|
||
root_domain = irq_domain_add_legacy(intc, NR_CPU_IRQS, 0, 0, | ||
&arcv2_irq_ops, NULL); | ||
|
||
if (!root_domain) | ||
panic("root irq domain not avail\n"); | ||
|
||
/* with this we don't need to export root_domain */ | ||
irq_set_default_host(root_domain); | ||
|
||
return 0; | ||
} | ||
|
||
IRQCHIP_DECLARE(arc_intc, "snps,archs-intc", init_onchip_IRQ); |