diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2012-10-26 08:39:56 -0400 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2012-10-26 08:39:56 -0400 |
| commit | e4de6c961cc8b688443c7989ae3e38d0518334a5 (patch) | |
| tree | a9c806d2e79675699b15ec97f8e8f75f5b53b611 | |
| parent | 6f0c0580b70c89094b3422ba81118c7b959c7556 (diff) | |
| parent | 6f35f9a9fabe8f0a89a17e353a77a7edef461bb2 (diff) | |
Merge tag 'armsoc-for-3.8' of git://server.prisktech.co.nz/git/linuxwmt into next/multiplatform
From Tony Prisk <linux@prisktech.co.nz>:
Convert arch-vt8500 to multiplatform
* tag 'armsoc-for-3.8' of git://server.prisktech.co.nz/git/linuxwmt:
ARM: vt8500: Convert arch-vt8500 to multiplatform
arm: vt8500: Convert irq.c for multiplatform integration
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
| -rw-r--r-- | arch/arm/Kconfig | 6 | ||||
| -rw-r--r-- | arch/arm/mach-vt8500/Kconfig | 12 | ||||
| -rw-r--r-- | arch/arm/mach-vt8500/common.h | 3 | ||||
| -rw-r--r-- | arch/arm/mach-vt8500/include/mach/entry-macro.S | 26 | ||||
| -rw-r--r-- | arch/arm/mach-vt8500/include/mach/irqs.h | 22 | ||||
| -rw-r--r-- | arch/arm/mach-vt8500/irq.c | 108 | ||||
| -rw-r--r-- | arch/arm/mach-vt8500/vt8500.c | 1 |
7 files changed, 91 insertions, 87 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 73067efd4845..2a262a8ef7e9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -941,7 +941,7 @@ config ARCH_OMAP | |||
| 941 | help | 941 | help |
| 942 | Support for TI's OMAP platform (OMAP1/2/3/4). | 942 | Support for TI's OMAP platform (OMAP1/2/3/4). |
| 943 | 943 | ||
| 944 | config ARCH_VT8500 | 944 | config ARCH_VT8500_SINGLE |
| 945 | bool "VIA/WonderMedia 85xx" | 945 | bool "VIA/WonderMedia 85xx" |
| 946 | select ARCH_HAS_CPUFREQ | 946 | select ARCH_HAS_CPUFREQ |
| 947 | select ARCH_REQUIRE_GPIOLIB | 947 | select ARCH_REQUIRE_GPIOLIB |
| @@ -951,6 +951,8 @@ config ARCH_VT8500 | |||
| 951 | select GENERIC_CLOCKEVENTS | 951 | select GENERIC_CLOCKEVENTS |
| 952 | select GENERIC_GPIO | 952 | select GENERIC_GPIO |
| 953 | select HAVE_CLK | 953 | select HAVE_CLK |
| 954 | select MULTI_IRQ_HANDLER | ||
| 955 | select SPARSE_IRQ | ||
| 954 | select USE_OF | 956 | select USE_OF |
| 955 | help | 957 | help |
| 956 | Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. | 958 | Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. |
| @@ -1126,6 +1128,8 @@ source "arch/arm/mach-versatile/Kconfig" | |||
| 1126 | source "arch/arm/mach-vexpress/Kconfig" | 1128 | source "arch/arm/mach-vexpress/Kconfig" |
| 1127 | source "arch/arm/plat-versatile/Kconfig" | 1129 | source "arch/arm/plat-versatile/Kconfig" |
| 1128 | 1130 | ||
| 1131 | source "arch/arm/mach-vt8500/Kconfig" | ||
| 1132 | |||
| 1129 | source "arch/arm/mach-w90x900/Kconfig" | 1133 | source "arch/arm/mach-w90x900/Kconfig" |
| 1130 | 1134 | ||
| 1131 | # Definitions to make life easier | 1135 | # Definitions to make life easier |
diff --git a/arch/arm/mach-vt8500/Kconfig b/arch/arm/mach-vt8500/Kconfig new file mode 100644 index 000000000000..2ed0b7d95db6 --- /dev/null +++ b/arch/arm/mach-vt8500/Kconfig | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | config ARCH_VT8500 | ||
| 2 | bool "VIA/WonderMedia 85xx" if ARCH_MULTI_V5 | ||
| 3 | default ARCH_VT8500_SINGLE | ||
| 4 | select ARCH_HAS_CPUFREQ | ||
| 5 | select ARCH_REQUIRE_GPIOLIB | ||
| 6 | select CLKDEV_LOOKUP | ||
| 7 | select CPU_ARM926T | ||
| 8 | select GENERIC_CLOCKEVENTS | ||
| 9 | select GENERIC_GPIO | ||
| 10 | select HAVE_CLK | ||
| 11 | help | ||
| 12 | Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. | ||
diff --git a/arch/arm/mach-vt8500/common.h b/arch/arm/mach-vt8500/common.h index 2b2419646e95..6f2b843115db 100644 --- a/arch/arm/mach-vt8500/common.h +++ b/arch/arm/mach-vt8500/common.h | |||
| @@ -25,4 +25,7 @@ int __init vt8500_irq_init(struct device_node *node, | |||
| 25 | /* defined in drivers/clk/clk-vt8500.c */ | 25 | /* defined in drivers/clk/clk-vt8500.c */ |
| 26 | void __init vtwm_clk_init(void __iomem *pmc_base); | 26 | void __init vtwm_clk_init(void __iomem *pmc_base); |
| 27 | 27 | ||
| 28 | /* defined in irq.c */ | ||
| 29 | asmlinkage void vt8500_handle_irq(struct pt_regs *regs); | ||
| 30 | |||
| 28 | #endif | 31 | #endif |
diff --git a/arch/arm/mach-vt8500/include/mach/entry-macro.S b/arch/arm/mach-vt8500/include/mach/entry-macro.S deleted file mode 100644 index 367d1b55fb9a..000000000000 --- a/arch/arm/mach-vt8500/include/mach/entry-macro.S +++ /dev/null | |||
| @@ -1,26 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm/mach-vt8500/include/mach/entry-macro.S | ||
| 3 | * | ||
| 4 | * Low-level IRQ helper macros for VIA VT8500 | ||
| 5 | * | ||
| 6 | * This file is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2. This program is licensed "as is" without any | ||
| 8 | * warranty of any kind, whether express or implied. | ||
| 9 | */ | ||
| 10 | |||
| 11 | .macro get_irqnr_preamble, base, tmp | ||
| 12 | @ physical 0xd8140000 is virtual 0xf8140000 | ||
| 13 | mov \base, #0xf8000000 | ||
| 14 | orr \base, \base, #0x00140000 | ||
| 15 | .endm | ||
| 16 | |||
| 17 | .macro get_irqnr_and_base, irqnr, irqstat, base, tmp | ||
| 18 | ldr \irqnr, [\base] | ||
| 19 | cmp \irqnr, #63 @ may be false positive, check interrupt status | ||
| 20 | bne 1001f | ||
| 21 | ldr \irqstat, [\base, #0x84] | ||
| 22 | ands \irqstat, #0x80000000 | ||
| 23 | moveq \irqnr, #0 | ||
| 24 | 1001: | ||
| 25 | .endm | ||
| 26 | |||
diff --git a/arch/arm/mach-vt8500/include/mach/irqs.h b/arch/arm/mach-vt8500/include/mach/irqs.h deleted file mode 100644 index a129fd1222fb..000000000000 --- a/arch/arm/mach-vt8500/include/mach/irqs.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm/mach-vt8500/include/mach/irqs.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* This value is just to make the core happy, never used otherwise */ | ||
| 22 | #define NR_IRQS 128 | ||
diff --git a/arch/arm/mach-vt8500/irq.c b/arch/arm/mach-vt8500/irq.c index f8f9ab9bc56e..b9cf5ce9efbb 100644 --- a/arch/arm/mach-vt8500/irq.c +++ b/arch/arm/mach-vt8500/irq.c | |||
| @@ -36,7 +36,7 @@ | |||
| 36 | #include <linux/of_address.h> | 36 | #include <linux/of_address.h> |
| 37 | 37 | ||
| 38 | #include <asm/irq.h> | 38 | #include <asm/irq.h> |
| 39 | 39 | #include <asm/exception.h> | |
| 40 | 40 | ||
| 41 | #define VT8500_ICPC_IRQ 0x20 | 41 | #define VT8500_ICPC_IRQ 0x20 |
| 42 | #define VT8500_ICPC_FIQ 0x24 | 42 | #define VT8500_ICPC_FIQ 0x24 |
| @@ -66,30 +66,34 @@ | |||
| 66 | #define VT8500_EDGE ( VT8500_TRIGGER_RISING \ | 66 | #define VT8500_EDGE ( VT8500_TRIGGER_RISING \ |
| 67 | | VT8500_TRIGGER_FALLING) | 67 | | VT8500_TRIGGER_FALLING) |
| 68 | 68 | ||
| 69 | static int irq_cnt; | 69 | /* vt8500 has 1 intc, wm8505 and wm8650 have 2 */ |
| 70 | #define VT8500_INTC_MAX 2 | ||
| 70 | 71 | ||
| 71 | struct vt8500_irq_priv { | 72 | struct vt8500_irq_data { |
| 72 | void __iomem *base; | 73 | void __iomem *base; /* IO Memory base address */ |
| 74 | struct irq_domain *domain; /* Domain for this controller */ | ||
| 73 | }; | 75 | }; |
| 74 | 76 | ||
| 77 | /* Global variable for accessing io-mem addresses */ | ||
| 78 | static struct vt8500_irq_data intc[VT8500_INTC_MAX]; | ||
| 79 | static u32 active_cnt = 0; | ||
| 80 | |||
| 75 | static void vt8500_irq_mask(struct irq_data *d) | 81 | static void vt8500_irq_mask(struct irq_data *d) |
| 76 | { | 82 | { |
| 77 | struct vt8500_irq_priv *priv = | 83 | struct vt8500_irq_data *priv = d->domain->host_data; |
| 78 | (struct vt8500_irq_priv *)(d->domain->host_data); | ||
| 79 | void __iomem *base = priv->base; | 84 | void __iomem *base = priv->base; |
| 80 | u8 edge; | 85 | void __iomem *stat_reg = base + VT8500_ICIS + (d->hwirq < 32 ? 0 : 4); |
| 86 | u8 edge, dctr; | ||
| 87 | u32 status; | ||
| 81 | 88 | ||
| 82 | edge = readb(base + VT8500_ICDC + d->hwirq) & VT8500_EDGE; | 89 | edge = readb(base + VT8500_ICDC + d->hwirq) & VT8500_EDGE; |
| 83 | if (edge) { | 90 | if (edge) { |
| 84 | void __iomem *stat_reg = base + VT8500_ICIS | 91 | status = readl(stat_reg); |
| 85 | + (d->hwirq < 32 ? 0 : 4); | ||
| 86 | unsigned status = readl(stat_reg); | ||
| 87 | 92 | ||
| 88 | status |= (1 << (d->hwirq & 0x1f)); | 93 | status |= (1 << (d->hwirq & 0x1f)); |
| 89 | writel(status, stat_reg); | 94 | writel(status, stat_reg); |
| 90 | } else { | 95 | } else { |
| 91 | u8 dctr = readb(base + VT8500_ICDC + d->hwirq); | 96 | dctr = readb(base + VT8500_ICDC + d->hwirq); |
| 92 | |||
| 93 | dctr &= ~VT8500_INT_ENABLE; | 97 | dctr &= ~VT8500_INT_ENABLE; |
| 94 | writeb(dctr, base + VT8500_ICDC + d->hwirq); | 98 | writeb(dctr, base + VT8500_ICDC + d->hwirq); |
| 95 | } | 99 | } |
| @@ -97,8 +101,7 @@ static void vt8500_irq_mask(struct irq_data *d) | |||
| 97 | 101 | ||
| 98 | static void vt8500_irq_unmask(struct irq_data *d) | 102 | static void vt8500_irq_unmask(struct irq_data *d) |
| 99 | { | 103 | { |
| 100 | struct vt8500_irq_priv *priv = | 104 | struct vt8500_irq_data *priv = d->domain->host_data; |
| 101 | (struct vt8500_irq_priv *)(d->domain->host_data); | ||
| 102 | void __iomem *base = priv->base; | 105 | void __iomem *base = priv->base; |
| 103 | u8 dctr; | 106 | u8 dctr; |
| 104 | 107 | ||
| @@ -109,8 +112,7 @@ static void vt8500_irq_unmask(struct irq_data *d) | |||
| 109 | 112 | ||
| 110 | static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type) | 113 | static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type) |
| 111 | { | 114 | { |
| 112 | struct vt8500_irq_priv *priv = | 115 | struct vt8500_irq_data *priv = d->domain->host_data; |
| 113 | (struct vt8500_irq_priv *)(d->domain->host_data); | ||
| 114 | void __iomem *base = priv->base; | 116 | void __iomem *base = priv->base; |
| 115 | u8 dctr; | 117 | u8 dctr; |
| 116 | 118 | ||
| @@ -148,17 +150,15 @@ static struct irq_chip vt8500_irq_chip = { | |||
| 148 | 150 | ||
| 149 | static void __init vt8500_init_irq_hw(void __iomem *base) | 151 | static void __init vt8500_init_irq_hw(void __iomem *base) |
| 150 | { | 152 | { |
| 151 | unsigned int i; | 153 | u32 i; |
| 152 | 154 | ||
| 153 | /* Enable rotating priority for IRQ */ | 155 | /* Enable rotating priority for IRQ */ |
| 154 | writel(ICPC_ROTATE, base + VT8500_ICPC_IRQ); | 156 | writel(ICPC_ROTATE, base + VT8500_ICPC_IRQ); |
| 155 | writel(0x00, base + VT8500_ICPC_FIQ); | 157 | writel(0x00, base + VT8500_ICPC_FIQ); |
| 156 | 158 | ||
| 157 | for (i = 0; i < 64; i++) { | 159 | /* Disable all interrupts and route them to IRQ */ |
| 158 | /* Disable all interrupts and route them to IRQ */ | 160 | for (i = 0; i < 64; i++) |
| 159 | writeb(VT8500_INT_DISABLE | ICDC_IRQ, | 161 | writeb(VT8500_INT_DISABLE | ICDC_IRQ, base + VT8500_ICDC + i); |
| 160 | base + VT8500_ICDC + i); | ||
| 161 | } | ||
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static int vt8500_irq_map(struct irq_domain *h, unsigned int virq, | 164 | static int vt8500_irq_map(struct irq_domain *h, unsigned int virq, |
| @@ -175,33 +175,67 @@ static struct irq_domain_ops vt8500_irq_domain_ops = { | |||
| 175 | .xlate = irq_domain_xlate_onecell, | 175 | .xlate = irq_domain_xlate_onecell, |
| 176 | }; | 176 | }; |
| 177 | 177 | ||
| 178 | asmlinkage void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs) | ||
| 179 | { | ||
| 180 | u32 stat, i; | ||
| 181 | int irqnr, virq; | ||
| 182 | void __iomem *base; | ||
| 183 | |||
| 184 | /* Loop through each active controller */ | ||
| 185 | for (i=0; i<active_cnt; i++) { | ||
| 186 | base = intc[i].base; | ||
| 187 | irqnr = readl_relaxed(base) & 0x3F; | ||
| 188 | /* | ||
| 189 | Highest Priority register default = 63, so check that this | ||
| 190 | is a real interrupt by checking the status register | ||
| 191 | */ | ||
| 192 | if (irqnr == 63) { | ||
| 193 | stat = readl_relaxed(base + VT8500_ICIS + 4); | ||
| 194 | if (!(stat & BIT(31))) | ||
| 195 | continue; | ||
| 196 | } | ||
| 197 | |||
| 198 | virq = irq_find_mapping(intc[i].domain, irqnr); | ||
| 199 | handle_IRQ(virq, regs); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 178 | int __init vt8500_irq_init(struct device_node *node, struct device_node *parent) | 203 | int __init vt8500_irq_init(struct device_node *node, struct device_node *parent) |
| 179 | { | 204 | { |
| 180 | struct irq_domain *vt8500_irq_domain; | ||
| 181 | struct vt8500_irq_priv *priv; | ||
| 182 | int irq, i; | 205 | int irq, i; |
| 183 | struct device_node *np = node; | 206 | struct device_node *np = node; |
| 184 | 207 | ||
| 185 | priv = kzalloc(sizeof(struct vt8500_irq_priv), GFP_KERNEL); | 208 | if (active_cnt == VT8500_INTC_MAX) { |
| 186 | priv->base = of_iomap(np, 0); | 209 | pr_err("%s: Interrupt controllers > VT8500_INTC_MAX\n", |
| 210 | __func__); | ||
| 211 | goto out; | ||
| 212 | } | ||
| 213 | |||
| 214 | intc[active_cnt].base = of_iomap(np, 0); | ||
| 215 | intc[active_cnt].domain = irq_domain_add_linear(node, 64, | ||
| 216 | &vt8500_irq_domain_ops, &intc[active_cnt]); | ||
| 187 | 217 | ||
| 188 | vt8500_irq_domain = irq_domain_add_legacy(node, 64, irq_cnt, 0, | 218 | if (!intc[active_cnt].base) { |
| 189 | &vt8500_irq_domain_ops, priv); | 219 | pr_err("%s: Unable to map IO memory\n", __func__); |
| 190 | if (!vt8500_irq_domain) | 220 | goto out; |
| 191 | pr_err("%s: Unable to add wmt irq domain!\n", __func__); | 221 | } |
| 222 | |||
| 223 | if (!intc[active_cnt].domain) { | ||
| 224 | pr_err("%s: Unable to add irq domain!\n", __func__); | ||
| 225 | goto out; | ||
| 226 | } | ||
| 192 | 227 | ||
| 193 | irq_set_default_host(vt8500_irq_domain); | 228 | vt8500_init_irq_hw(intc[active_cnt].base); |
| 194 | 229 | ||
| 195 | vt8500_init_irq_hw(priv->base); | 230 | pr_info("vt8500-irq: Added interrupt controller\n"); |
| 196 | 231 | ||
| 197 | pr_info("Added IRQ Controller @ %x [virq_base = %d]\n", | 232 | active_cnt++; |
| 198 | (u32)(priv->base), irq_cnt); | ||
| 199 | 233 | ||
| 200 | /* check if this is a slaved controller */ | 234 | /* check if this is a slaved controller */ |
| 201 | if (of_irq_count(np) != 0) { | 235 | if (of_irq_count(np) != 0) { |
| 202 | /* check that we have the correct number of interrupts */ | 236 | /* check that we have the correct number of interrupts */ |
| 203 | if (of_irq_count(np) != 8) { | 237 | if (of_irq_count(np) != 8) { |
| 204 | pr_err("%s: Incorrect IRQ map for slave controller\n", | 238 | pr_err("%s: Incorrect IRQ map for slaved controller\n", |
| 205 | __func__); | 239 | __func__); |
| 206 | return -EINVAL; | 240 | return -EINVAL; |
| 207 | } | 241 | } |
| @@ -213,9 +247,7 @@ int __init vt8500_irq_init(struct device_node *node, struct device_node *parent) | |||
| 213 | 247 | ||
| 214 | pr_info("vt8500-irq: Enabled slave->parent interrupts\n"); | 248 | pr_info("vt8500-irq: Enabled slave->parent interrupts\n"); |
| 215 | } | 249 | } |
| 216 | 250 | out: | |
| 217 | irq_cnt += 64; | ||
| 218 | |||
| 219 | return 0; | 251 | return 0; |
| 220 | } | 252 | } |
| 221 | 253 | ||
diff --git a/arch/arm/mach-vt8500/vt8500.c b/arch/arm/mach-vt8500/vt8500.c index 8d3871f110a5..14def0f9eab0 100644 --- a/arch/arm/mach-vt8500/vt8500.c +++ b/arch/arm/mach-vt8500/vt8500.c | |||
| @@ -194,5 +194,6 @@ DT_MACHINE_START(WMT_DT, "VIA/Wondermedia SoC (Device Tree Support)") | |||
| 194 | .timer = &vt8500_timer, | 194 | .timer = &vt8500_timer, |
| 195 | .init_machine = vt8500_init, | 195 | .init_machine = vt8500_init, |
| 196 | .restart = vt8500_restart, | 196 | .restart = vt8500_restart, |
| 197 | .handle_irq = vt8500_handle_irq, | ||
| 197 | MACHINE_END | 198 | MACHINE_END |
| 198 | 199 | ||
