diff options
-rw-r--r-- | arch/arm/plat-mxc/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/plat-mxc/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/common.h | 1 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/entry-macro.S | 34 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/irqs.h | 6 | ||||
-rw-r--r-- | arch/arm/plat-mxc/tzic.c | 172 |
6 files changed, 222 insertions, 2 deletions
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index 8b0a1ee039fa..59558c4b9446 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig | |||
@@ -62,6 +62,14 @@ config MXC_IRQ_PRIOR | |||
62 | requirements for timing. | 62 | requirements for timing. |
63 | Say N here, unless you have a specialized requirement. | 63 | Say N here, unless you have a specialized requirement. |
64 | 64 | ||
65 | config MXC_TZIC | ||
66 | bool "Enable TrustZone Interrupt Controller" | ||
67 | depends on ARCH_MX51 | ||
68 | help | ||
69 | This will be automatically selected for all processors | ||
70 | containing this interrupt controller. | ||
71 | Say N here only if you are really sure. | ||
72 | |||
65 | config MXC_PWM | 73 | config MXC_PWM |
66 | tristate "Enable PWM driver" | 74 | tristate "Enable PWM driver" |
67 | depends on ARCH_MXC | 75 | depends on ARCH_MXC |
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 7322bca8f5fb..a4bc6cb26aa4 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile | |||
@@ -5,6 +5,9 @@ | |||
5 | # Common support | 5 | # Common support |
6 | obj-y := irq.o clock.o gpio.o time.o devices.o cpu.o system.o | 6 | obj-y := irq.o clock.o gpio.o time.o devices.o cpu.o system.o |
7 | 7 | ||
8 | # MX51 uses the TZIC interrupt controller, older platforms use AVIC (irq.o) | ||
9 | obj-$(CONFIG_MXC_TZIC) += tzic.o | ||
10 | |||
8 | obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o | 11 | obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o |
9 | obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o | 12 | obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o |
10 | CFLAGS_iomux-mx1-mx2.o = -DIMX_NEEDS_DEPRECATED_SYMBOLS | 13 | CFLAGS_iomux-mx1-mx2.o = -DIMX_NEEDS_DEPRECATED_SYMBOLS |
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index 4bf1068ffad9..1394025068c3 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h | |||
@@ -22,6 +22,7 @@ extern void mx31_map_io(void); | |||
22 | extern void mx35_map_io(void); | 22 | extern void mx35_map_io(void); |
23 | extern void mxc91231_map_io(void); | 23 | extern void mxc91231_map_io(void); |
24 | extern void mxc_init_irq(void __iomem *); | 24 | extern void mxc_init_irq(void __iomem *); |
25 | extern void tzic_init_irq(void __iomem *); | ||
25 | extern void mx1_init_irq(void); | 26 | extern void mx1_init_irq(void); |
26 | extern void mx21_init_irq(void); | 27 | extern void mx21_init_irq(void); |
27 | extern void mx25_init_irq(void); | 28 | extern void mx25_init_irq(void); |
diff --git a/arch/arm/plat-mxc/include/mach/entry-macro.S b/arch/arm/plat-mxc/include/mach/entry-macro.S index 7cf290efe768..aeb08697726b 100644 --- a/arch/arm/plat-mxc/include/mach/entry-macro.S +++ b/arch/arm/plat-mxc/include/mach/entry-macro.S | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org> | 2 | * Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org> |
3 | * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. | 3 | * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. |
4 | */ | 4 | */ |
5 | 5 | ||
6 | /* | 6 | /* |
@@ -18,11 +18,16 @@ | |||
18 | .endm | 18 | .endm |
19 | 19 | ||
20 | .macro get_irqnr_preamble, base, tmp | 20 | .macro get_irqnr_preamble, base, tmp |
21 | #ifndef CONFIG_MXC_TZIC | ||
21 | ldr \base, =avic_base | 22 | ldr \base, =avic_base |
22 | ldr \base, [\base] | 23 | ldr \base, [\base] |
23 | #ifdef CONFIG_MXC_IRQ_PRIOR | 24 | #ifdef CONFIG_MXC_IRQ_PRIOR |
24 | ldr r4, [\base, #AVIC_NIMASK] | 25 | ldr r4, [\base, #AVIC_NIMASK] |
25 | #endif | 26 | #endif |
27 | #elif defined CONFIG_MXC_TZIC | ||
28 | ldr \base, =tzic_base | ||
29 | ldr \base, [\base] | ||
30 | #endif /* CONFIG_MXC_TZIC */ | ||
26 | .endm | 31 | .endm |
27 | 32 | ||
28 | .macro arch_ret_to_user, tmp1, tmp2 | 33 | .macro arch_ret_to_user, tmp1, tmp2 |
@@ -32,6 +37,7 @@ | |||
32 | @ and returns its number in irqnr | 37 | @ and returns its number in irqnr |
33 | @ and returns if an interrupt occured in irqstat | 38 | @ and returns if an interrupt occured in irqstat |
34 | .macro get_irqnr_and_base, irqnr, irqstat, base, tmp | 39 | .macro get_irqnr_and_base, irqnr, irqstat, base, tmp |
40 | #ifndef CONFIG_MXC_TZIC | ||
35 | @ Load offset & priority of the highest priority | 41 | @ Load offset & priority of the highest priority |
36 | @ interrupt pending from AVIC_NIVECSR | 42 | @ interrupt pending from AVIC_NIVECSR |
37 | ldr \irqstat, [\base, #0x40] | 43 | ldr \irqstat, [\base, #0x40] |
@@ -45,6 +51,32 @@ | |||
45 | strne \tmp, [\base, #AVIC_NIMASK] | 51 | strne \tmp, [\base, #AVIC_NIMASK] |
46 | streq r4, [\base, #AVIC_NIMASK] | 52 | streq r4, [\base, #AVIC_NIMASK] |
47 | #endif | 53 | #endif |
54 | #elif defined CONFIG_MXC_TZIC | ||
55 | @ Load offset & priority of the highest priority | ||
56 | @ interrupt pending. | ||
57 | @ 0xD80 is HIPND0 register | ||
58 | mov \irqnr, #0 | ||
59 | mov \irqstat, #0x0D80 | ||
60 | 1000: | ||
61 | ldr \tmp, [\irqstat, \base] | ||
62 | cmp \tmp, #0 | ||
63 | bne 1001f | ||
64 | addeq \irqnr, \irqnr, #32 | ||
65 | addeq \irqstat, \irqstat, #4 | ||
66 | cmp \irqnr, #128 | ||
67 | blo 1000b | ||
68 | b 2001f | ||
69 | 1001: mov \irqstat, #1 | ||
70 | 1002: tst \tmp, \irqstat | ||
71 | bne 2002f | ||
72 | movs \tmp, \tmp, lsr #1 | ||
73 | addne \irqnr, \irqnr, #1 | ||
74 | bne 1002b | ||
75 | 2001: | ||
76 | mov \irqnr, #0 | ||
77 | 2002: | ||
78 | movs \irqnr, \irqnr | ||
79 | #endif | ||
48 | .endm | 80 | .endm |
49 | 81 | ||
50 | @ irq priority table (not used) | 82 | @ irq priority table (not used) |
diff --git a/arch/arm/plat-mxc/include/mach/irqs.h b/arch/arm/plat-mxc/include/mach/irqs.h index 0cb347645db4..38f150162e45 100644 --- a/arch/arm/plat-mxc/include/mach/irqs.h +++ b/arch/arm/plat-mxc/include/mach/irqs.h | |||
@@ -12,9 +12,13 @@ | |||
12 | #define __ASM_ARCH_MXC_IRQS_H__ | 12 | #define __ASM_ARCH_MXC_IRQS_H__ |
13 | 13 | ||
14 | /* | 14 | /* |
15 | * So far all i.MX SoCs have 64 internal interrupts | 15 | * SoCs with TZIC interrupt controller have 128 IRQs, those with AVIC have 64 |
16 | */ | 16 | */ |
17 | #ifdef CONFIG_MXC_TZIC | ||
18 | #define MXC_INTERNAL_IRQS 128 | ||
19 | #else | ||
17 | #define MXC_INTERNAL_IRQS 64 | 20 | #define MXC_INTERNAL_IRQS 64 |
21 | #endif | ||
18 | 22 | ||
19 | #define MXC_GPIO_IRQ_START MXC_INTERNAL_IRQS | 23 | #define MXC_GPIO_IRQ_START MXC_INTERNAL_IRQS |
20 | 24 | ||
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 | } | ||