diff options
author | John Rigby <jrigby@freescale.com> | 2008-07-09 16:54:04 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2008-07-12 14:10:55 -0400 |
commit | 1879f711d8c3960e0fd927f38ff885017a77291b (patch) | |
tree | 39c71df0060b858f7bab85abcef3fefce116f061 /arch/powerpc/platforms/512x | |
parent | fb1803224ea145e3424d6295d4aaa8e9fef70642 (diff) |
powerpc/mpc5121: Add support for CPLD on MPC5121ADS board
Add a interrupt host for the interrupt controller in the mpc5121ads cpld.
PCI interrupts are 0-7 the rest are 8-15 Touchscreen pendown irq is
hardwired to irq1 All other irqs are chained to irq0
Signed-off-by: John Rigby <jrigby@freescale.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'arch/powerpc/platforms/512x')
-rw-r--r-- | arch/powerpc/platforms/512x/Kconfig | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_ads.c | 11 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_ads.h | 16 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | 204 |
5 files changed, 233 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index 5d72dc3435af..c62f893ede19 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig | |||
@@ -13,6 +13,7 @@ config MPC5121_ADS | |||
13 | depends on PPC_MULTIPLATFORM && PPC32 | 13 | depends on PPC_MULTIPLATFORM && PPC32 |
14 | select DEFAULT_UIMAGE | 14 | select DEFAULT_UIMAGE |
15 | select PPC_MPC5121 | 15 | select PPC_MPC5121 |
16 | select MPC5121_ADS_CPLD | ||
16 | help | 17 | help |
17 | This option enables support for the MPC5121E ADS board. | 18 | This option enables support for the MPC5121E ADS board. |
18 | 19 | ||
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile index 8090e222a2dd..90be2f5717e6 100644 --- a/arch/powerpc/platforms/512x/Makefile +++ b/arch/powerpc/platforms/512x/Makefile | |||
@@ -2,5 +2,5 @@ | |||
2 | # Makefile for the Freescale PowerPC 512x linux kernel. | 2 | # Makefile for the Freescale PowerPC 512x linux kernel. |
3 | # | 3 | # |
4 | obj-y += clock.o mpc512x_shared.o | 4 | obj-y += clock.o mpc512x_shared.o |
5 | obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o | 5 | obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o mpc5121_ads_cpld.o |
6 | obj-$(CONFIG_MPC5121_GENERIC) += mpc5121_generic.o | 6 | obj-$(CONFIG_MPC5121_GENERIC) += mpc5121_generic.o |
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c index 3ec9ca34d8e8..5ebf6939a697 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c | |||
@@ -23,10 +23,21 @@ | |||
23 | #include <asm/time.h> | 23 | #include <asm/time.h> |
24 | 24 | ||
25 | #include "mpc512x.h" | 25 | #include "mpc512x.h" |
26 | #include "mpc5121_ads.h" | ||
27 | |||
28 | static void __init mpc5121_ads_setup_arch(void) | ||
29 | { | ||
30 | printk(KERN_INFO "MPC5121 ADS board from Freescale Semiconductor\n"); | ||
31 | /* | ||
32 | * cpld regs are needed early | ||
33 | */ | ||
34 | mpc5121_ads_cpld_map(); | ||
35 | } | ||
26 | 36 | ||
27 | static void __init mpc5121_ads_init_IRQ(void) | 37 | static void __init mpc5121_ads_init_IRQ(void) |
28 | { | 38 | { |
29 | mpc512x_init_IRQ(); | 39 | mpc512x_init_IRQ(); |
40 | mpc5121_ads_cpld_pic_init(); | ||
30 | } | 41 | } |
31 | 42 | ||
32 | /* | 43 | /* |
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.h b/arch/powerpc/platforms/512x/mpc5121_ads.h new file mode 100644 index 000000000000..662076cfee2f --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_ads.h | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | * | ||
9 | * Prototypes for ADS5121 specific code | ||
10 | */ | ||
11 | |||
12 | #ifndef __MPC512ADS_H__ | ||
13 | #define __MPC512ADS_H__ | ||
14 | extern void __init mpc5121_ads_cpld_map(void); | ||
15 | extern void __init mpc5121_ads_cpld_pic_init(void); | ||
16 | #endif /* __MPC512ADS_H__ */ | ||
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c new file mode 100644 index 000000000000..a6ce80566625 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Author: John Rigby, <jrigby@freescale.com> | ||
5 | * | ||
6 | * Description: | ||
7 | * MPC5121ADS CPLD irq handling | ||
8 | * | ||
9 | * This is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #undef DEBUG | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <asm/prom.h> | ||
22 | |||
23 | static struct device_node *cpld_pic_node; | ||
24 | static struct irq_host *cpld_pic_host; | ||
25 | |||
26 | /* | ||
27 | * Bits to ignore in the misc_status register | ||
28 | * 0x10 touch screen pendown is hard routed to irq1 | ||
29 | * 0x02 pci status is read from pci status register | ||
30 | */ | ||
31 | #define MISC_IGNORE 0x12 | ||
32 | |||
33 | /* | ||
34 | * Nothing to ignore in pci status register | ||
35 | */ | ||
36 | #define PCI_IGNORE 0x00 | ||
37 | |||
38 | struct cpld_pic { | ||
39 | u8 pci_mask; | ||
40 | u8 pci_status; | ||
41 | u8 route; | ||
42 | u8 misc_mask; | ||
43 | u8 misc_status; | ||
44 | u8 misc_control; | ||
45 | }; | ||
46 | |||
47 | static struct cpld_pic __iomem *cpld_regs; | ||
48 | |||
49 | static void __iomem * | ||
50 | irq_to_pic_mask(unsigned int irq) | ||
51 | { | ||
52 | return irq <= 7 ? &cpld_regs->pci_mask : &cpld_regs->misc_mask; | ||
53 | } | ||
54 | |||
55 | static unsigned int | ||
56 | irq_to_pic_bit(unsigned int irq) | ||
57 | { | ||
58 | return 1 << (irq & 0x7); | ||
59 | } | ||
60 | |||
61 | static void | ||
62 | cpld_mask_irq(unsigned int irq) | ||
63 | { | ||
64 | unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq; | ||
65 | void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); | ||
66 | |||
67 | out_8(pic_mask, | ||
68 | in_8(pic_mask) | irq_to_pic_bit(cpld_irq)); | ||
69 | } | ||
70 | |||
71 | static void | ||
72 | cpld_unmask_irq(unsigned int irq) | ||
73 | { | ||
74 | unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq; | ||
75 | void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); | ||
76 | |||
77 | out_8(pic_mask, | ||
78 | in_8(pic_mask) & ~irq_to_pic_bit(cpld_irq)); | ||
79 | } | ||
80 | |||
81 | static struct irq_chip cpld_pic = { | ||
82 | .typename = " CPLD PIC ", | ||
83 | .mask = cpld_mask_irq, | ||
84 | .ack = cpld_mask_irq, | ||
85 | .unmask = cpld_unmask_irq, | ||
86 | }; | ||
87 | |||
88 | static int | ||
89 | cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp, | ||
90 | u8 __iomem *maskp) | ||
91 | { | ||
92 | int cpld_irq; | ||
93 | u8 status = in_8(statusp); | ||
94 | u8 mask = in_8(maskp); | ||
95 | |||
96 | /* ignore don't cares and masked irqs */ | ||
97 | status |= (ignore | mask); | ||
98 | |||
99 | if (status == 0xff) | ||
100 | return NO_IRQ_IGNORE; | ||
101 | |||
102 | cpld_irq = ffz(status) + offset; | ||
103 | |||
104 | return irq_linear_revmap(cpld_pic_host, cpld_irq); | ||
105 | } | ||
106 | |||
107 | static void | ||
108 | cpld_pic_cascade(unsigned int irq, struct irq_desc *desc) | ||
109 | { | ||
110 | irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status, | ||
111 | &cpld_regs->pci_mask); | ||
112 | if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { | ||
113 | generic_handle_irq(irq); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status, | ||
118 | &cpld_regs->misc_mask); | ||
119 | if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { | ||
120 | generic_handle_irq(irq); | ||
121 | return; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | static int | ||
126 | cpld_pic_host_match(struct irq_host *h, struct device_node *node) | ||
127 | { | ||
128 | return cpld_pic_node == node; | ||
129 | } | ||
130 | |||
131 | static int | ||
132 | cpld_pic_host_map(struct irq_host *h, unsigned int virq, | ||
133 | irq_hw_number_t hw) | ||
134 | { | ||
135 | get_irq_desc(virq)->status |= IRQ_LEVEL; | ||
136 | set_irq_chip_and_handler(virq, &cpld_pic, handle_level_irq); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static struct | ||
141 | irq_host_ops cpld_pic_host_ops = { | ||
142 | .match = cpld_pic_host_match, | ||
143 | .map = cpld_pic_host_map, | ||
144 | }; | ||
145 | |||
146 | void __init | ||
147 | mpc5121_ads_cpld_map(void) | ||
148 | { | ||
149 | struct device_node *np = NULL; | ||
150 | |||
151 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic"); | ||
152 | if (!np) { | ||
153 | printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n"); | ||
154 | return; | ||
155 | } | ||
156 | |||
157 | cpld_regs = of_iomap(np, 0); | ||
158 | of_node_put(np); | ||
159 | } | ||
160 | |||
161 | void __init | ||
162 | mpc5121_ads_cpld_pic_init(void) | ||
163 | { | ||
164 | unsigned int cascade_irq; | ||
165 | struct device_node *np = NULL; | ||
166 | |||
167 | pr_debug("cpld_ic_init\n"); | ||
168 | |||
169 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic"); | ||
170 | if (!np) { | ||
171 | printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n"); | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | if (!cpld_regs) | ||
176 | goto end; | ||
177 | |||
178 | cascade_irq = irq_of_parse_and_map(np, 0); | ||
179 | if (cascade_irq == NO_IRQ) | ||
180 | goto end; | ||
181 | |||
182 | /* | ||
183 | * statically route touch screen pendown through 1 | ||
184 | * and ignore it here | ||
185 | * route all others through our cascade irq | ||
186 | */ | ||
187 | out_8(&cpld_regs->route, 0xfd); | ||
188 | out_8(&cpld_regs->pci_mask, 0xff); | ||
189 | /* unmask pci ints in misc mask */ | ||
190 | out_8(&cpld_regs->misc_mask, ~(MISC_IGNORE)); | ||
191 | |||
192 | cpld_pic_node = of_node_get(np); | ||
193 | |||
194 | cpld_pic_host = | ||
195 | irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16); | ||
196 | if (!cpld_pic_host) { | ||
197 | printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n"); | ||
198 | goto end; | ||
199 | } | ||
200 | |||
201 | set_irq_chained_handler(cascade_irq, cpld_pic_cascade); | ||
202 | end: | ||
203 | of_node_put(np); | ||
204 | } | ||