diff options
| -rw-r--r-- | arch/arm/mach-tegra/include/mach/irqs.h | 2 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/irq.c | 137 |
2 files changed, 139 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/include/mach/irqs.h b/arch/arm/mach-tegra/include/mach/irqs.h index 20f640edaa0d..71bbf3422953 100644 --- a/arch/arm/mach-tegra/include/mach/irqs.h +++ b/arch/arm/mach-tegra/include/mach/irqs.h | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | 25 | ||
| 26 | #define IRQ_LOCALTIMER 29 | 26 | #define IRQ_LOCALTIMER 29 |
| 27 | 27 | ||
| 28 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
| 28 | /* Primary Interrupt Controller */ | 29 | /* Primary Interrupt Controller */ |
| 29 | #define INT_PRI_BASE (INT_GIC_BASE + 32) | 30 | #define INT_PRI_BASE (INT_GIC_BASE + 32) |
| 30 | #define INT_TMR1 (INT_PRI_BASE + 0) | 31 | #define INT_TMR1 (INT_PRI_BASE + 0) |
| @@ -169,5 +170,6 @@ | |||
| 169 | #define INT_GPIO_NR (28 * 8) | 170 | #define INT_GPIO_NR (28 * 8) |
| 170 | 171 | ||
| 171 | #define NR_IRQS (INT_GPIO_BASE + INT_GPIO_NR) | 172 | #define NR_IRQS (INT_GPIO_BASE + INT_GPIO_NR) |
| 173 | #endif | ||
| 172 | 174 | ||
| 173 | #endif | 175 | #endif |
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 1fdbe708d43d..50a8dfb9a0cf 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | * Author: | 4 | * Author: |
| 5 | * Colin Cross <ccross@google.com> | 5 | * Colin Cross <ccross@google.com> |
| 6 | * | 6 | * |
| 7 | * Copyright (C) 2010, NVIDIA Corporation | ||
| 8 | * | ||
| 7 | * This software is licensed under the terms of the GNU General Public | 9 | * This software is licensed under the terms of the GNU General Public |
| 8 | * License version 2, as published by the Free Software Foundation, and | 10 | * License version 2, as published by the Free Software Foundation, and |
| 9 | * may be copied, distributed, and modified under those terms. | 11 | * may be copied, distributed, and modified under those terms. |
| @@ -27,8 +29,143 @@ | |||
| 27 | 29 | ||
| 28 | #include "board.h" | 30 | #include "board.h" |
| 29 | 31 | ||
| 32 | #define INT_SYS_NR (INT_GPIO_BASE - INT_PRI_BASE) | ||
| 33 | #define INT_SYS_SZ (INT_SEC_BASE - INT_PRI_BASE) | ||
| 34 | #define PPI_NR ((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ) | ||
| 35 | |||
| 36 | #define APBDMA_IRQ_STA_CPU 0x14 | ||
| 37 | #define APBDMA_IRQ_MASK_SET 0x20 | ||
| 38 | #define APBDMA_IRQ_MASK_CLR 0x24 | ||
| 39 | |||
| 40 | #define ICTLR_CPU_IER 0x20 | ||
| 41 | #define ICTLR_CPU_IER_SET 0x24 | ||
| 42 | #define ICTLR_CPU_IER_CLR 0x28 | ||
| 43 | #define ICTLR_CPU_IEP_CLASS 0x2c | ||
| 44 | #define ICTLR_COP_IER 0x30 | ||
| 45 | #define ICTLR_COP_IER_SET 0x34 | ||
| 46 | #define ICTLR_COP_IER_CLR 0x38 | ||
| 47 | #define ICTLR_COP_IEP_CLASS 0x3c | ||
| 48 | |||
| 49 | static void (*gic_mask_irq)(unsigned int irq); | ||
| 50 | static void (*gic_unmask_irq)(unsigned int irq); | ||
| 51 | |||
| 52 | #define irq_to_ictlr(irq) (((irq)-32) >> 5) | ||
| 53 | static void __iomem *tegra_ictlr_base = IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE); | ||
| 54 | #define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr)*0x100) | ||
| 55 | |||
| 56 | static void tegra_mask(unsigned int irq) | ||
| 57 | { | ||
| 58 | void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq)); | ||
| 59 | gic_mask_irq(irq); | ||
| 60 | writel(1<<(irq&31), addr+ICTLR_CPU_IER_CLR); | ||
| 61 | } | ||
| 62 | |||
| 63 | static void tegra_unmask(unsigned int irq) | ||
| 64 | { | ||
| 65 | void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq)); | ||
| 66 | gic_unmask_irq(irq); | ||
| 67 | writel(1<<(irq&31), addr+ICTLR_CPU_IER_SET); | ||
| 68 | } | ||
| 69 | |||
| 70 | #ifdef CONFIG_PM | ||
| 71 | |||
| 72 | static int tegra_set_wake(unsigned int irq, unsigned int on) | ||
| 73 | { | ||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | #endif | ||
| 77 | |||
| 78 | static struct irq_chip tegra_irq = { | ||
| 79 | .name = "PPI", | ||
| 80 | .mask = tegra_mask, | ||
| 81 | .unmask = tegra_unmask, | ||
| 82 | #ifdef CONFIG_PM | ||
| 83 | .set_wake = tegra_set_wake, | ||
| 84 | #endif | ||
| 85 | }; | ||
| 86 | |||
| 30 | void __init tegra_init_irq(void) | 87 | void __init tegra_init_irq(void) |
| 31 | { | 88 | { |
| 89 | struct irq_chip *gic; | ||
| 90 | unsigned int i; | ||
| 91 | |||
| 92 | for (i = 0; i < PPI_NR; i++) { | ||
| 93 | writel(~0, ictlr_to_virt(i) + ICTLR_CPU_IER_CLR); | ||
| 94 | writel(0, ictlr_to_virt(i) + ICTLR_CPU_IEP_CLASS); | ||
| 95 | } | ||
| 96 | |||
| 32 | gic_dist_init(0, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE), 29); | 97 | gic_dist_init(0, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE), 29); |
| 33 | gic_cpu_init(0, IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100)); | 98 | gic_cpu_init(0, IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100)); |
| 99 | |||
| 100 | gic = get_irq_chip(29); | ||
| 101 | gic_unmask_irq = gic->unmask; | ||
| 102 | gic_mask_irq = gic->mask; | ||
| 103 | tegra_irq.ack = gic->ack; | ||
| 104 | #ifdef CONFIG_SMP | ||
| 105 | tegra_irq.set_affinity = gic->set_affinity; | ||
| 106 | #endif | ||
| 107 | |||
| 108 | for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) { | ||
| 109 | set_irq_chip(i, &tegra_irq); | ||
| 110 | set_irq_handler(i, handle_level_irq); | ||
| 111 | set_irq_flags(i, IRQF_VALID); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | #ifdef CONFIG_PM | ||
| 116 | static u32 cop_ier[PPI_NR]; | ||
| 117 | static u32 cpu_ier[PPI_NR]; | ||
| 118 | static u32 cpu_iep[PPI_NR]; | ||
| 119 | |||
| 120 | void tegra_irq_suspend(void) | ||
| 121 | { | ||
| 122 | unsigned long flags; | ||
| 123 | int i; | ||
| 124 | |||
| 125 | for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) { | ||
| 126 | struct irq_desc *desc = irq_to_desc(i); | ||
| 127 | if (!desc) | ||
| 128 | continue; | ||
| 129 | if (desc->status & IRQ_WAKEUP) { | ||
| 130 | pr_debug("irq %d is wakeup\n", i); | ||
| 131 | continue; | ||
| 132 | } | ||
| 133 | disable_irq(i); | ||
| 134 | } | ||
| 135 | |||
| 136 | local_irq_save(flags); | ||
| 137 | for (i = 0; i < PPI_NR; i++) { | ||
| 138 | void __iomem *ictlr = ictlr_to_virt(i); | ||
| 139 | cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER); | ||
| 140 | cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS); | ||
| 141 | cop_ier[i] = readl(ictlr + ICTLR_COP_IER); | ||
| 142 | writel(~0, ictlr + ICTLR_COP_IER_CLR); | ||
| 143 | } | ||
| 144 | local_irq_restore(flags); | ||
| 145 | } | ||
| 146 | |||
| 147 | void tegra_irq_resume(void) | ||
| 148 | { | ||
| 149 | unsigned long flags; | ||
| 150 | int i; | ||
| 151 | |||
| 152 | local_irq_save(flags); | ||
| 153 | for (i = 0; i < PPI_NR; i++) { | ||
| 154 | void __iomem *ictlr = ictlr_to_virt(i); | ||
| 155 | writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS); | ||
| 156 | writel(~0ul, ictlr + ICTLR_CPU_IER_CLR); | ||
| 157 | writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET); | ||
| 158 | writel(0, ictlr + ICTLR_COP_IEP_CLASS); | ||
| 159 | writel(~0ul, ictlr + ICTLR_COP_IER_CLR); | ||
| 160 | writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET); | ||
| 161 | } | ||
| 162 | local_irq_restore(flags); | ||
| 163 | |||
| 164 | for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) { | ||
| 165 | struct irq_desc *desc = irq_to_desc(i); | ||
| 166 | if (!desc || (desc->status & IRQ_WAKEUP)) | ||
| 167 | continue; | ||
| 168 | enable_irq(i); | ||
| 169 | } | ||
| 34 | } | 170 | } |
| 171 | #endif | ||
