2 * Copyright (C) 2010 Google, Inc.
5 * Colin Cross <ccross@google.com>
7 * Copyright (C) 2010, NVIDIA Corporation
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
20 #include <linux/kernel.h>
21 #include <linux/init.h>
22 #include <linux/interrupt.h>
23 #include <linux/irq.h>
26 #include <asm/hardware/gic.h>
28 #include <mach/iomap.h>
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)
36 #define APBDMA_IRQ_STA_CPU 0x14
37 #define APBDMA_IRQ_MASK_SET 0x20
38 #define APBDMA_IRQ_MASK_CLR 0x24
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
49 static void (*tegra_gic_mask_irq
)(struct irq_data
*d
);
50 static void (*tegra_gic_unmask_irq
)(struct irq_data
*d
);
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)
56 static void tegra_mask(struct irq_data
*d
)
58 void __iomem
*addr
= ictlr_to_virt(irq_to_ictlr(d
->irq
));
59 tegra_gic_mask_irq(d
);
60 writel(1 << (d
->irq
& 31), addr
+ICTLR_CPU_IER_CLR
);
63 static void tegra_unmask(struct irq_data
*d
)
65 void __iomem
*addr
= ictlr_to_virt(irq_to_ictlr(d
->irq
));
66 tegra_gic_unmask_irq(d
);
67 writel(1<<(d
->irq
&31), addr
+ICTLR_CPU_IER_SET
);
72 static int tegra_set_wake(struct irq_data
*d
, unsigned int on
)
78 static struct irq_chip tegra_irq
= {
80 .irq_mask
= tegra_mask
,
81 .irq_unmask
= tegra_unmask
,
83 .irq_set_wake
= tegra_set_wake
,
87 void __init
tegra_init_irq(void)
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
);
97 gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE
),
98 IO_ADDRESS(TEGRA_ARM_PERIF_BASE
+ 0x100));
100 gic
= get_irq_chip(29);
101 tegra_gic_unmask_irq
= gic
->irq_unmask
;
102 tegra_gic_mask_irq
= gic
->irq_mask
;
103 tegra_irq
.irq_ack
= gic
->irq_ack
;
105 tegra_irq
.irq_set_affinity
= gic
->irq_set_affinity
;
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
);
116 static u32 cop_ier
[PPI_NR
];
117 static u32 cpu_ier
[PPI_NR
];
118 static u32 cpu_iep
[PPI_NR
];
120 void tegra_irq_suspend(void)
125 for (i
= INT_PRI_BASE
; i
< INT_GPIO_BASE
; i
++) {
126 struct irq_desc
*desc
= irq_to_desc(i
);
129 if (desc
->status
& IRQ_WAKEUP
) {
130 pr_debug("irq %d is wakeup\n", i
);
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
);
144 local_irq_restore(flags
);
147 void tegra_irq_resume(void)
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
);
162 local_irq_restore(flags
);
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
))