aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorAmit Kucheria <amit.kucheria@canonical.com>2009-12-03 15:36:41 -0500
committerAmit Kucheria <amit.kucheria@canonical.com>2010-02-09 09:15:26 -0500
commita003708ad4ee9384226251431c7953a24079ff80 (patch)
tree03062bf18e6d688338c46015682f80aba7d458db /arch/arm
parentcb2dc111b156eb41f61ed4e5b3a3a5df90526d9d (diff)
mxc: TrustZone interrupt controller (TZIC) for Freescale i.MX5 family
Freescale i.MX51 processor uses a new interrupt controller. Add driver for TrustZone Interrupt Controller Signed-off-by: Amit Kucheria <amit.kucheria@canonical.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/plat-mxc/Kconfig8
-rw-r--r--arch/arm/plat-mxc/Makefile3
-rw-r--r--arch/arm/plat-mxc/include/mach/common.h1
-rw-r--r--arch/arm/plat-mxc/include/mach/entry-macro.S34
-rw-r--r--arch/arm/plat-mxc/include/mach/irqs.h6
-rw-r--r--arch/arm/plat-mxc/tzic.c172
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
65config 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
65config MXC_PWM 73config 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
6obj-y := irq.o clock.o gpio.o time.o devices.o cpu.o system.o 6obj-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)
9obj-$(CONFIG_MXC_TZIC) += tzic.o
10
8obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o 11obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o
9obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o 12obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o
10CFLAGS_iomux-mx1-mx2.o = -DIMX_NEEDS_DEPRECATED_SYMBOLS 13CFLAGS_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);
22extern void mx35_map_io(void); 22extern void mx35_map_io(void);
23extern void mxc91231_map_io(void); 23extern void mxc91231_map_io(void);
24extern void mxc_init_irq(void __iomem *); 24extern void mxc_init_irq(void __iomem *);
25extern void tzic_init_irq(void __iomem *);
25extern void mx1_init_irq(void); 26extern void mx1_init_irq(void);
26extern void mx21_init_irq(void); 27extern void mx21_init_irq(void);
27extern void mx25_init_irq(void); 28extern 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
601000:
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
691001: mov \irqstat, #1
701002: tst \tmp, \irqstat
71 bne 2002f
72 movs \tmp, \tmp, lsr #1
73 addne \irqnr, \irqnr, #1
74 bne 1002b
752001:
76 mov \irqnr, #0
772002:
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
47void __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 */
54static 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 */
68static 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
77static 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 */
88static 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
106static 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 */
119void __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 */
158int 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}