diff options
Diffstat (limited to 'arch/arm/plat-mxc/tzic.c')
-rw-r--r-- | arch/arm/plat-mxc/tzic.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/arch/arm/plat-mxc/tzic.c b/arch/arm/plat-mxc/tzic.c new file mode 100644 index 000000000000..afa6709db0b3 --- /dev/null +++ b/arch/arm/plat-mxc/tzic.c | |||
@@ -0,0 +1,172 @@ | |||
1 | /* | ||
2 | * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/io.h> | ||
18 | |||
19 | #include <asm/mach/irq.h> | ||
20 | |||
21 | #include <mach/hardware.h> | ||
22 | |||
23 | /* | ||
24 | ***************************************** | ||
25 | * TZIC Registers * | ||
26 | ***************************************** | ||
27 | */ | ||
28 | |||
29 | #define TZIC_INTCNTL 0x0000 /* Control register */ | ||
30 | #define TZIC_INTTYPE 0x0004 /* Controller Type register */ | ||
31 | #define TZIC_IMPID 0x0008 /* Distributor Implementer Identification */ | ||
32 | #define TZIC_PRIOMASK 0x000C /* Priority Mask Reg */ | ||
33 | #define TZIC_SYNCCTRL 0x0010 /* Synchronizer Control register */ | ||
34 | #define TZIC_DSMINT 0x0014 /* DSM interrupt Holdoffregister */ | ||
35 | #define TZIC_INTSEC0(i) (0x0080 + ((i) << 2)) /* Interrupt Security Reg 0 */ | ||
36 | #define TZIC_ENSET0(i) (0x0100 + ((i) << 2)) /* Enable Set Reg 0 */ | ||
37 | #define TZIC_ENCLEAR0(i) (0x0180 + ((i) << 2)) /* Enable Clear Reg 0 */ | ||
38 | #define TZIC_SRCSET0 0x0200 /* Source Set Register 0 */ | ||
39 | #define TZIC_SRCCLAR0 0x0280 /* Source Clear Register 0 */ | ||
40 | #define TZIC_PRIORITY0 0x0400 /* Priority Register 0 */ | ||
41 | #define TZIC_PND0 0x0D00 /* Pending Register 0 */ | ||
42 | #define TZIC_HIPND0 0x0D80 /* High Priority Pending Register */ | ||
43 | #define TZIC_WAKEUP0(i) (0x0E00 + ((i) << 2)) /* Wakeup Config Register */ | ||
44 | #define TZIC_SWINT 0x0F00 /* Software Interrupt Rigger Register */ | ||
45 | #define TZIC_ID0 0x0FD0 /* Indentification Register 0 */ | ||
46 | |||
47 | void __iomem *tzic_base; /* Used as irq controller base in entry-macro.S */ | ||
48 | |||
49 | /** | ||
50 | * tzic_mask_irq() - Disable interrupt number "irq" in the TZIC | ||
51 | * | ||
52 | * @param irq interrupt source number | ||
53 | */ | ||
54 | static void tzic_mask_irq(unsigned int irq) | ||
55 | { | ||
56 | int index, off; | ||
57 | |||
58 | index = irq >> 5; | ||
59 | off = irq & 0x1F; | ||
60 | __raw_writel(1 << off, tzic_base + TZIC_ENCLEAR0(index)); | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * tzic_unmask_irq() - Enable interrupt number "irq" in the TZIC | ||
65 | * | ||
66 | * @param irq interrupt source number | ||
67 | */ | ||
68 | static void tzic_unmask_irq(unsigned int irq) | ||
69 | { | ||
70 | int index, off; | ||
71 | |||
72 | index = irq >> 5; | ||
73 | off = irq & 0x1F; | ||
74 | __raw_writel(1 << off, tzic_base + TZIC_ENSET0(index)); | ||
75 | } | ||
76 | |||
77 | static unsigned int wakeup_intr[4]; | ||
78 | |||
79 | /** | ||
80 | * tzic_set_wake_irq() - Set interrupt number "irq" in the TZIC as a wake-up source. | ||
81 | * | ||
82 | * @param irq interrupt source number | ||
83 | * @param enable enable as wake-up if equal to non-zero | ||
84 | * disble as wake-up if equal to zero | ||
85 | * | ||
86 | * @return This function returns 0 on success. | ||
87 | */ | ||
88 | static int tzic_set_wake_irq(unsigned int irq, unsigned int enable) | ||
89 | { | ||
90 | unsigned int index, off; | ||
91 | |||
92 | index = irq >> 5; | ||
93 | off = irq & 0x1F; | ||
94 | |||
95 | if (index > 3) | ||
96 | return -EINVAL; | ||
97 | |||
98 | if (enable) | ||
99 | wakeup_intr[index] |= (1 << off); | ||
100 | else | ||
101 | wakeup_intr[index] &= ~(1 << off); | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static struct irq_chip mxc_tzic_chip = { | ||
107 | .name = "MXC_TZIC", | ||
108 | .ack = tzic_mask_irq, | ||
109 | .mask = tzic_mask_irq, | ||
110 | .unmask = tzic_unmask_irq, | ||
111 | .set_wake = tzic_set_wake_irq, | ||
112 | }; | ||
113 | |||
114 | /* | ||
115 | * This function initializes the TZIC hardware and disables all the | ||
116 | * interrupts. It registers the interrupt enable and disable functions | ||
117 | * to the kernel for each interrupt source. | ||
118 | */ | ||
119 | void __init tzic_init_irq(void __iomem *irqbase) | ||
120 | { | ||
121 | int i; | ||
122 | |||
123 | tzic_base = irqbase; | ||
124 | /* put the TZIC into the reset value with | ||
125 | * all interrupts disabled | ||
126 | */ | ||
127 | i = __raw_readl(tzic_base + TZIC_INTCNTL); | ||
128 | |||
129 | __raw_writel(0x80010001, tzic_base + TZIC_INTCNTL); | ||
130 | __raw_writel(0x1f, tzic_base + TZIC_PRIOMASK); | ||
131 | __raw_writel(0x02, tzic_base + TZIC_SYNCCTRL); | ||
132 | |||
133 | for (i = 0; i < 4; i++) | ||
134 | __raw_writel(0xFFFFFFFF, tzic_base + TZIC_INTSEC0(i)); | ||
135 | |||
136 | /* disable all interrupts */ | ||
137 | for (i = 0; i < 4; i++) | ||
138 | __raw_writel(0xFFFFFFFF, tzic_base + TZIC_ENCLEAR0(i)); | ||
139 | |||
140 | /* all IRQ no FIQ Warning :: No selection */ | ||
141 | |||
142 | for (i = 0; i < MXC_INTERNAL_IRQS; i++) { | ||
143 | set_irq_chip(i, &mxc_tzic_chip); | ||
144 | set_irq_handler(i, handle_level_irq); | ||
145 | set_irq_flags(i, IRQF_VALID); | ||
146 | } | ||
147 | |||
148 | pr_info("TrustZone Interrupt Controller (TZIC) initialized\n"); | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * tzic_enable_wake() - enable wakeup interrupt | ||
153 | * | ||
154 | * @param is_idle 1 if called in idle loop (ENSET0 register); | ||
155 | * 0 to be used when called from low power entry | ||
156 | * @return 0 if successful; non-zero otherwise | ||
157 | */ | ||
158 | int tzic_enable_wake(int is_idle) | ||
159 | { | ||
160 | unsigned int i, v; | ||
161 | |||
162 | __raw_writel(1, tzic_base + TZIC_DSMINT); | ||
163 | if (unlikely(__raw_readl(tzic_base + TZIC_DSMINT) == 0)) | ||
164 | return -EAGAIN; | ||
165 | |||
166 | for (i = 0; i < 4; i++) { | ||
167 | v = is_idle ? __raw_readl(TZIC_ENSET0(i)) : wakeup_intr[i]; | ||
168 | __raw_writel(v, TZIC_WAKEUP0(i)); | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||