diff options
author | Peter Horton <phorton@bitbox.co.uk> | 2010-12-06 06:37:38 -0500 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2010-12-14 03:54:37 -0500 |
commit | cdc3f10630ecddb7870e087ff9679eef3d7b4e21 (patch) | |
tree | bcffe39f52a334e9ad8e56b15843a42e228988da | |
parent | 8be9252f7ccde4148e4b203bf64d38ae66b111e4 (diff) |
mx51: support FIQ on TZIC, revised
Add support for FIQ on mx51 TZIC
TZIC changes tested with FIQ audio on an mx51 board
AVIC changes build with mx3_defconfig, not tested
Signed-off-by: Peter Horton <phorton@bitbox.co.uk>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r-- | arch/arm/plat-mxc/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/plat-mxc/avic.c | 32 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/entry-macro.S | 14 | ||||
-rw-r--r-- | arch/arm/plat-mxc/irq-common.c | 60 | ||||
-rw-r--r-- | arch/arm/plat-mxc/irq-common.h | 29 | ||||
-rw-r--r-- | arch/arm/plat-mxc/tzic.c | 46 |
6 files changed, 155 insertions, 28 deletions
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 989cb59e67ac..5fd20e96876c 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # Common support | 5 | # Common support |
6 | obj-y := clock.o gpio.o time.o devices.o cpu.o system.o | 6 | obj-y := clock.o gpio.o time.o devices.o cpu.o system.o irq-common.o |
7 | 7 | ||
8 | # MX51 uses the TZIC interrupt controller, older platforms use AVIC | 8 | # MX51 uses the TZIC interrupt controller, older platforms use AVIC |
9 | obj-$(CONFIG_MXC_TZIC) += tzic.o | 9 | obj-$(CONFIG_MXC_TZIC) += tzic.o |
diff --git a/arch/arm/plat-mxc/avic.c b/arch/arm/plat-mxc/avic.c index 7331f2ace5fe..9a4e8a22dd0a 100644 --- a/arch/arm/plat-mxc/avic.c +++ b/arch/arm/plat-mxc/avic.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include <asm/mach/irq.h> | 24 | #include <asm/mach/irq.h> |
25 | #include <mach/hardware.h> | 25 | #include <mach/hardware.h> |
26 | 26 | ||
27 | #include "irq-common.h" | ||
28 | |||
27 | #define AVIC_INTCNTL 0x00 /* int control reg */ | 29 | #define AVIC_INTCNTL 0x00 /* int control reg */ |
28 | #define AVIC_NIMASK 0x04 /* int mask reg */ | 30 | #define AVIC_NIMASK 0x04 /* int mask reg */ |
29 | #define AVIC_INTENNUM 0x08 /* int enable number reg */ | 31 | #define AVIC_INTENNUM 0x08 /* int enable number reg */ |
@@ -46,9 +48,9 @@ | |||
46 | 48 | ||
47 | void __iomem *avic_base; | 49 | void __iomem *avic_base; |
48 | 50 | ||
49 | int imx_irq_set_priority(unsigned char irq, unsigned char prio) | ||
50 | { | ||
51 | #ifdef CONFIG_MXC_IRQ_PRIOR | 51 | #ifdef CONFIG_MXC_IRQ_PRIOR |
52 | static int avic_irq_set_priority(unsigned char irq, unsigned char prio) | ||
53 | { | ||
52 | unsigned int temp; | 54 | unsigned int temp; |
53 | unsigned int mask = 0x0F << irq % 8 * 4; | 55 | unsigned int mask = 0x0F << irq % 8 * 4; |
54 | 56 | ||
@@ -62,14 +64,11 @@ int imx_irq_set_priority(unsigned char irq, unsigned char prio) | |||
62 | __raw_writel(temp, avic_base + AVIC_NIPRIORITY(irq / 8)); | 64 | __raw_writel(temp, avic_base + AVIC_NIPRIORITY(irq / 8)); |
63 | 65 | ||
64 | return 0; | 66 | return 0; |
65 | #else | ||
66 | return -ENOSYS; | ||
67 | #endif | ||
68 | } | 67 | } |
69 | EXPORT_SYMBOL(imx_irq_set_priority); | 68 | #endif |
70 | 69 | ||
71 | #ifdef CONFIG_FIQ | 70 | #ifdef CONFIG_FIQ |
72 | int mxc_set_irq_fiq(unsigned int irq, unsigned int type) | 71 | static int avic_set_irq_fiq(unsigned int irq, unsigned int type) |
73 | { | 72 | { |
74 | unsigned int irqt; | 73 | unsigned int irqt; |
75 | 74 | ||
@@ -87,7 +86,6 @@ int mxc_set_irq_fiq(unsigned int irq, unsigned int type) | |||
87 | 86 | ||
88 | return 0; | 87 | return 0; |
89 | } | 88 | } |
90 | EXPORT_SYMBOL(mxc_set_irq_fiq); | ||
91 | #endif /* CONFIG_FIQ */ | 89 | #endif /* CONFIG_FIQ */ |
92 | 90 | ||
93 | /* Disable interrupt number "irq" in the AVIC */ | 91 | /* Disable interrupt number "irq" in the AVIC */ |
@@ -102,10 +100,18 @@ static void mxc_unmask_irq(unsigned int irq) | |||
102 | __raw_writel(irq, avic_base + AVIC_INTENNUM); | 100 | __raw_writel(irq, avic_base + AVIC_INTENNUM); |
103 | } | 101 | } |
104 | 102 | ||
105 | static struct irq_chip mxc_avic_chip = { | 103 | static struct mxc_irq_chip mxc_avic_chip = { |
106 | .ack = mxc_mask_irq, | 104 | .base = { |
107 | .mask = mxc_mask_irq, | 105 | .ack = mxc_mask_irq, |
108 | .unmask = mxc_unmask_irq, | 106 | .mask = mxc_mask_irq, |
107 | .unmask = mxc_unmask_irq, | ||
108 | }, | ||
109 | #ifdef CONFIG_MXC_IRQ_PRIOR | ||
110 | .set_priority = avic_irq_set_priority, | ||
111 | #endif | ||
112 | #ifdef CONFIG_FIQ | ||
113 | .set_irq_fiq = avic_set_irq_fiq, | ||
114 | #endif | ||
109 | }; | 115 | }; |
110 | 116 | ||
111 | /* | 117 | /* |
@@ -133,7 +139,7 @@ void __init mxc_init_irq(void __iomem *irqbase) | |||
133 | __raw_writel(0, avic_base + AVIC_INTTYPEH); | 139 | __raw_writel(0, avic_base + AVIC_INTTYPEH); |
134 | __raw_writel(0, avic_base + AVIC_INTTYPEL); | 140 | __raw_writel(0, avic_base + AVIC_INTTYPEL); |
135 | for (i = 0; i < MXC_INTERNAL_IRQS; i++) { | 141 | for (i = 0; i < MXC_INTERNAL_IRQS; i++) { |
136 | set_irq_chip(i, &mxc_avic_chip); | 142 | set_irq_chip(i, &mxc_avic_chip.base); |
137 | set_irq_handler(i, handle_level_irq); | 143 | set_irq_handler(i, handle_level_irq); |
138 | set_irq_flags(i, IRQF_VALID); | 144 | set_irq_flags(i, IRQF_VALID); |
139 | } | 145 | } |
diff --git a/arch/arm/plat-mxc/include/mach/entry-macro.S b/arch/arm/plat-mxc/include/mach/entry-macro.S index aeb08697726b..bd9bb9799141 100644 --- a/arch/arm/plat-mxc/include/mach/entry-macro.S +++ b/arch/arm/plat-mxc/include/mach/entry-macro.S | |||
@@ -54,15 +54,15 @@ | |||
54 | #elif defined CONFIG_MXC_TZIC | 54 | #elif defined CONFIG_MXC_TZIC |
55 | @ Load offset & priority of the highest priority | 55 | @ Load offset & priority of the highest priority |
56 | @ interrupt pending. | 56 | @ interrupt pending. |
57 | @ 0x080 is INTSEC0 register | ||
57 | @ 0xD80 is HIPND0 register | 58 | @ 0xD80 is HIPND0 register |
58 | mov \irqnr, #0 | 59 | mov \irqnr, #0 |
59 | mov \irqstat, #0x0D80 | 60 | 1000: add \irqstat, \base, \irqnr, lsr #3 |
60 | 1000: | 61 | ldr \tmp, [\irqstat, #0xd80] |
61 | ldr \tmp, [\irqstat, \base] | 62 | ldr \irqstat, [\irqstat, #0x080] |
62 | cmp \tmp, #0 | 63 | ands \tmp, \tmp, \irqstat |
63 | bne 1001f | 64 | bne 1001f |
64 | addeq \irqnr, \irqnr, #32 | 65 | add \irqnr, \irqnr, #32 |
65 | addeq \irqstat, \irqstat, #4 | ||
66 | cmp \irqnr, #128 | 66 | cmp \irqnr, #128 |
67 | blo 1000b | 67 | blo 1000b |
68 | b 2001f | 68 | b 2001f |
diff --git a/arch/arm/plat-mxc/irq-common.c b/arch/arm/plat-mxc/irq-common.c new file mode 100644 index 000000000000..0c799ac27730 --- /dev/null +++ b/arch/arm/plat-mxc/irq-common.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * Copyright (C) BitBox Ltd 2010 | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
16 | * MA 02110-1301, USA. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/irq.h> | ||
21 | |||
22 | #include "irq-common.h" | ||
23 | |||
24 | int imx_irq_set_priority(unsigned char irq, unsigned char prio) | ||
25 | { | ||
26 | struct mxc_irq_chip *chip; | ||
27 | struct irq_chip *base; | ||
28 | int ret; | ||
29 | |||
30 | ret = -ENOSYS; | ||
31 | |||
32 | base = get_irq_chip(irq); | ||
33 | if (base) { | ||
34 | chip = container_of(base, struct mxc_irq_chip, base); | ||
35 | if (chip->set_priority) | ||
36 | ret = chip->set_priority(irq, prio); | ||
37 | } | ||
38 | |||
39 | return ret; | ||
40 | } | ||
41 | EXPORT_SYMBOL(imx_irq_set_priority); | ||
42 | |||
43 | int mxc_set_irq_fiq(unsigned int irq, unsigned int type) | ||
44 | { | ||
45 | struct mxc_irq_chip *chip; | ||
46 | struct irq_chip *base; | ||
47 | int ret; | ||
48 | |||
49 | ret = -ENOSYS; | ||
50 | |||
51 | base = get_irq_chip(irq); | ||
52 | if (base) { | ||
53 | chip = container_of(base, struct mxc_irq_chip, base); | ||
54 | if (chip->set_irq_fiq) | ||
55 | ret = chip->set_irq_fiq(irq, type); | ||
56 | } | ||
57 | |||
58 | return ret; | ||
59 | } | ||
60 | EXPORT_SYMBOL(mxc_set_irq_fiq); | ||
diff --git a/arch/arm/plat-mxc/irq-common.h b/arch/arm/plat-mxc/irq-common.h new file mode 100644 index 000000000000..7203543fb1b3 --- /dev/null +++ b/arch/arm/plat-mxc/irq-common.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Copyright (C) BitBox Ltd 2010 | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
16 | * MA 02110-1301, USA. | ||
17 | */ | ||
18 | |||
19 | #ifndef __PLAT_MXC_IRQ_COMMON_H__ | ||
20 | #define __PLAT_MXC_IRQ_COMMON_H__ | ||
21 | |||
22 | struct mxc_irq_chip | ||
23 | { | ||
24 | struct irq_chip base; | ||
25 | int (*set_priority)(unsigned char irq, unsigned char prio); | ||
26 | int (*set_irq_fiq)(unsigned int irq, unsigned int type); | ||
27 | }; | ||
28 | |||
29 | #endif | ||
diff --git a/arch/arm/plat-mxc/tzic.c b/arch/arm/plat-mxc/tzic.c index 3703ab28257f..e69ed8a8c203 100644 --- a/arch/arm/plat-mxc/tzic.c +++ b/arch/arm/plat-mxc/tzic.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <mach/hardware.h> | 21 | #include <mach/hardware.h> |
22 | #include <mach/common.h> | 22 | #include <mach/common.h> |
23 | 23 | ||
24 | #include "irq-common.h" | ||
25 | |||
24 | /* | 26 | /* |
25 | ***************************************** | 27 | ***************************************** |
26 | * TZIC Registers * | 28 | * TZIC Registers * |
@@ -47,6 +49,25 @@ | |||
47 | 49 | ||
48 | void __iomem *tzic_base; /* Used as irq controller base in entry-macro.S */ | 50 | void __iomem *tzic_base; /* Used as irq controller base in entry-macro.S */ |
49 | 51 | ||
52 | #ifdef CONFIG_FIQ | ||
53 | static int tzic_set_irq_fiq(unsigned int irq, unsigned int type) | ||
54 | { | ||
55 | unsigned int index, mask, value; | ||
56 | |||
57 | index = irq >> 5; | ||
58 | if (unlikely(index >= 4)) | ||
59 | return -EINVAL; | ||
60 | mask = 1U << (irq & 0x1F); | ||
61 | |||
62 | value = __raw_readl(tzic_base + TZIC_INTSEC0(index)) | mask; | ||
63 | if (type) | ||
64 | value &= ~mask; | ||
65 | __raw_writel(value, tzic_base + TZIC_INTSEC0(index)); | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | #endif | ||
70 | |||
50 | /** | 71 | /** |
51 | * tzic_mask_irq() - Disable interrupt number "irq" in the TZIC | 72 | * tzic_mask_irq() - Disable interrupt number "irq" in the TZIC |
52 | * | 73 | * |
@@ -104,12 +125,17 @@ static int tzic_set_wake_irq(unsigned int irq, unsigned int enable) | |||
104 | return 0; | 125 | return 0; |
105 | } | 126 | } |
106 | 127 | ||
107 | static struct irq_chip mxc_tzic_chip = { | 128 | static struct mxc_irq_chip mxc_tzic_chip = { |
108 | .name = "MXC_TZIC", | 129 | .base = { |
109 | .ack = tzic_mask_irq, | 130 | .name = "MXC_TZIC", |
110 | .mask = tzic_mask_irq, | 131 | .ack = tzic_mask_irq, |
111 | .unmask = tzic_unmask_irq, | 132 | .mask = tzic_mask_irq, |
112 | .set_wake = tzic_set_wake_irq, | 133 | .unmask = tzic_unmask_irq, |
134 | .set_wake = tzic_set_wake_irq, | ||
135 | }, | ||
136 | #ifdef CONFIG_FIQ | ||
137 | .set_irq_fiq = tzic_set_irq_fiq, | ||
138 | #endif | ||
113 | }; | 139 | }; |
114 | 140 | ||
115 | /* | 141 | /* |
@@ -141,10 +167,16 @@ void __init tzic_init_irq(void __iomem *irqbase) | |||
141 | /* all IRQ no FIQ Warning :: No selection */ | 167 | /* all IRQ no FIQ Warning :: No selection */ |
142 | 168 | ||
143 | for (i = 0; i < MXC_INTERNAL_IRQS; i++) { | 169 | for (i = 0; i < MXC_INTERNAL_IRQS; i++) { |
144 | set_irq_chip(i, &mxc_tzic_chip); | 170 | set_irq_chip(i, &mxc_tzic_chip.base); |
145 | set_irq_handler(i, handle_level_irq); | 171 | set_irq_handler(i, handle_level_irq); |
146 | set_irq_flags(i, IRQF_VALID); | 172 | set_irq_flags(i, IRQF_VALID); |
147 | } | 173 | } |
174 | |||
175 | #ifdef CONFIG_FIQ | ||
176 | /* Initialize FIQ */ | ||
177 | init_FIQ(); | ||
178 | #endif | ||
179 | |||
148 | pr_info("TrustZone Interrupt Controller (TZIC) initialized\n"); | 180 | pr_info("TrustZone Interrupt Controller (TZIC) initialized\n"); |
149 | } | 181 | } |
150 | 182 | ||