aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/85xx
diff options
context:
space:
mode:
authorWolfgang Grandegger <wg@grandegger.com>2009-03-22 09:58:43 -0400
committerKumar Gala <galak@kernel.crashing.org>2009-03-27 07:42:08 -0400
commit393adcacadeea407925348b1a59ae8509ecffb3c (patch)
treed1f8b185bca709c90d8f7da6e7947ceca815bfec /arch/powerpc/platforms/85xx
parenta6ecb7e96cb0c8db92af2c312df3df78d88b1f58 (diff)
powerpc/85xx: Add support for the "socrates" board (MPC8544).
Supported are Ethernet, serial console, I2C, I2C-based RTC and temperature sensors, NOR and NAND flash, PCI, USB, CAN and Lime display controller. The multiplexing of FPGA interrupts onto PowerPC interrupt lines is supported through our own fpga_pic interrupt controller driver. For example the SJA1000 controller is level low sensitive connected to fpga_pic line 2 and is routed to the second (of three) irq lines to the CPU: can@3,100 { compatible = "philips,sja1000"; reg = <3 0x100 0x80>; interrupts = <2 2>; interrupts = <2 8 1>; // number, type, routing interrupt-parent = <&fpga_pic>; }; Signed-off-by: Sergei Poselenov <sposelenov@emcraft.com> Signed-off-by: Yuri Tikhonov <yur@emcraft.com> Signed-off-by: Ilya Yanok <yanok@emcraft.com> Signed-off-by: Wolfgang Grandegger <wg@grandegger.com> Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Dmitry Rakhchev <rda@emcraft.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms/85xx')
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig6
-rw-r--r--arch/powerpc/platforms/85xx/Makefile1
-rw-r--r--arch/powerpc/platforms/85xx/socrates.c133
-rw-r--r--arch/powerpc/platforms/85xx/socrates_fpga_pic.c327
-rw-r--r--arch/powerpc/platforms/85xx/socrates_fpga_pic.h16
5 files changed, 483 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index b79dc710ed34..7f066adc068c 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -51,6 +51,12 @@ config MPC85xx_DS
51 help 51 help
52 This option enables support for the MPC85xx DS (MPC8544 DS) board 52 This option enables support for the MPC85xx DS (MPC8544 DS) board
53 53
54config SOCRATES
55 bool "Socrates"
56 select DEFAULT_UIMAGE
57 help
58 This option enables support for the Socrates board.
59
54config KSI8560 60config KSI8560
55 bool "Emerson KSI8560" 61 bool "Emerson KSI8560"
56 select DEFAULT_UIMAGE 62 select DEFAULT_UIMAGE
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index f0798c09980f..a857b35b9828 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -13,4 +13,5 @@ obj-$(CONFIG_STX_GP3) += stx_gp3.o
13obj-$(CONFIG_TQM85xx) += tqm85xx.o 13obj-$(CONFIG_TQM85xx) += tqm85xx.o
14obj-$(CONFIG_SBC8560) += sbc8560.o 14obj-$(CONFIG_SBC8560) += sbc8560.o
15obj-$(CONFIG_SBC8548) += sbc8548.o 15obj-$(CONFIG_SBC8548) += sbc8548.o
16obj-$(CONFIG_SOCRATES) += socrates.o socrates_fpga_pic.o
16obj-$(CONFIG_KSI8560) += ksi8560.o 17obj-$(CONFIG_KSI8560) += ksi8560.o
diff --git a/arch/powerpc/platforms/85xx/socrates.c b/arch/powerpc/platforms/85xx/socrates.c
new file mode 100644
index 000000000000..d0e8443b12c6
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/socrates.c
@@ -0,0 +1,133 @@
1/*
2 * Copyright (c) 2008 Emcraft Systems
3 * Sergei Poselenov <sposelenov@emcraft.com>
4 *
5 * Based on MPC8560 ADS and arch/ppc tqm85xx ports
6 *
7 * Maintained by Kumar Gala (see MAINTAINERS for contact information)
8 *
9 * Copyright 2008 Freescale Semiconductor Inc.
10 *
11 * Copyright (c) 2005-2006 DENX Software Engineering
12 * Stefan Roese <sr@denx.de>
13 *
14 * Based on original work by
15 * Kumar Gala <kumar.gala@freescale.com>
16 * Copyright 2004 Freescale Semiconductor Inc.
17 *
18 * This program is free software; you can redistribute it and/or modify it
19 * under the terms of the GNU General Public License as published by the
20 * Free Software Foundation; either version 2 of the License, or (at your
21 * option) any later version.
22 */
23
24#include <linux/stddef.h>
25#include <linux/kernel.h>
26#include <linux/pci.h>
27#include <linux/kdev_t.h>
28#include <linux/delay.h>
29#include <linux/seq_file.h>
30#include <linux/of_platform.h>
31
32#include <asm/system.h>
33#include <asm/time.h>
34#include <asm/machdep.h>
35#include <asm/pci-bridge.h>
36#include <asm/mpic.h>
37#include <asm/prom.h>
38#include <mm/mmu_decl.h>
39#include <asm/udbg.h>
40
41#include <sysdev/fsl_soc.h>
42#include <sysdev/fsl_pci.h>
43
44#include "socrates_fpga_pic.h"
45
46static void __init socrates_pic_init(void)
47{
48 struct mpic *mpic;
49 struct resource r;
50 struct device_node *np;
51
52 np = of_find_node_by_type(NULL, "open-pic");
53 if (!np) {
54 printk(KERN_ERR "Could not find open-pic node\n");
55 return;
56 }
57
58 if (of_address_to_resource(np, 0, &r)) {
59 printk(KERN_ERR "Could not map mpic register space\n");
60 of_node_put(np);
61 return;
62 }
63
64 mpic = mpic_alloc(np, r.start,
65 MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
66 0, 256, " OpenPIC ");
67 BUG_ON(mpic == NULL);
68 of_node_put(np);
69
70 mpic_init(mpic);
71
72 np = of_find_compatible_node(NULL, NULL, "abb,socrates-fpga-pic");
73 if (!np) {
74 printk(KERN_ERR "Could not find socrates-fpga-pic node\n");
75 return;
76 }
77 socrates_fpga_pic_init(np);
78 of_node_put(np);
79}
80
81/*
82 * Setup the architecture
83 */
84static void __init socrates_setup_arch(void)
85{
86#ifdef CONFIG_PCI
87 struct device_node *np;
88#endif
89
90 if (ppc_md.progress)
91 ppc_md.progress("socrates_setup_arch()", 0);
92
93#ifdef CONFIG_PCI
94 for_each_compatible_node(np, "pci", "fsl,mpc8540-pci")
95 fsl_add_bridge(np, 1);
96#endif
97}
98
99static struct of_device_id __initdata socrates_of_bus_ids[] = {
100 { .compatible = "simple-bus", },
101 { .compatible = "gianfar", },
102 {},
103};
104
105static void __init socrates_init(void)
106{
107 of_platform_bus_probe(NULL, socrates_of_bus_ids, NULL);
108}
109
110/*
111 * Called very early, device-tree isn't unflattened
112 */
113static int __init socrates_probe(void)
114{
115 unsigned long root = of_get_flat_dt_root();
116
117 if (of_flat_dt_is_compatible(root, "abb,socrates"))
118 return 1;
119
120 return 0;
121}
122
123define_machine(socrates) {
124 .name = "Socrates",
125 .probe = socrates_probe,
126 .setup_arch = socrates_setup_arch,
127 .init = socrates_init,
128 .init_IRQ = socrates_pic_init,
129 .get_irq = mpic_get_irq,
130 .restart = fsl_rstcr_restart,
131 .calibrate_decr = generic_calibrate_decr,
132 .progress = udbg_progress,
133};
diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
new file mode 100644
index 000000000000..60edf63d0157
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
@@ -0,0 +1,327 @@
1/*
2 * Copyright (C) 2008 Ilya Yanok, Emcraft Systems
3 *
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 */
10
11#include <linux/irq.h>
12#include <linux/of_platform.h>
13#include <linux/io.h>
14
15/*
16 * The FPGA supports 9 interrupt sources, which can be routed to 3
17 * interrupt request lines of the MPIC. The line to be used can be
18 * specified through the third cell of FDT property "interrupts".
19 */
20
21#define SOCRATES_FPGA_NUM_IRQS 9
22
23#define FPGA_PIC_IRQCFG (0x0)
24#define FPGA_PIC_IRQMASK(n) (0x4 + 0x4 * (n))
25
26#define SOCRATES_FPGA_IRQ_MASK ((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
27
28struct socrates_fpga_irq_info {
29 unsigned int irq_line;
30 int type;
31};
32
33/*
34 * Interrupt routing and type table
35 *
36 * IRQ_TYPE_NONE means the interrupt type is configurable,
37 * otherwise it's fixed to the specified value.
38 */
39static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
40 [0] = {0, IRQ_TYPE_NONE},
41 [1] = {0, IRQ_TYPE_LEVEL_HIGH},
42 [2] = {0, IRQ_TYPE_LEVEL_LOW},
43 [3] = {0, IRQ_TYPE_NONE},
44 [4] = {0, IRQ_TYPE_NONE},
45 [5] = {0, IRQ_TYPE_NONE},
46 [6] = {0, IRQ_TYPE_NONE},
47 [7] = {0, IRQ_TYPE_NONE},
48 [8] = {0, IRQ_TYPE_LEVEL_HIGH},
49};
50
51#define socrates_fpga_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
52
53static DEFINE_SPINLOCK(socrates_fpga_pic_lock);
54
55static void __iomem *socrates_fpga_pic_iobase;
56static struct irq_host *socrates_fpga_pic_irq_host;
57static unsigned int socrates_fpga_irqs[3];
58
59static inline uint32_t socrates_fpga_pic_read(int reg)
60{
61 return in_be32(socrates_fpga_pic_iobase + reg);
62}
63
64static inline void socrates_fpga_pic_write(int reg, uint32_t val)
65{
66 out_be32(socrates_fpga_pic_iobase + reg, val);
67}
68
69static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
70{
71 uint32_t cause;
72 unsigned long flags;
73 int i;
74
75 /* Check irq line routed to the MPIC */
76 for (i = 0; i < 3; i++) {
77 if (irq == socrates_fpga_irqs[i])
78 break;
79 }
80 if (i == 3)
81 return NO_IRQ;
82
83 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
84 cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
85 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
86 for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) {
87 if (cause >> (i + 16))
88 break;
89 }
90 return irq_linear_revmap(socrates_fpga_pic_irq_host,
91 (irq_hw_number_t)i);
92}
93
94void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc)
95{
96 unsigned int cascade_irq;
97
98 /*
99 * See if we actually have an interrupt, call generic handling code if
100 * we do.
101 */
102 cascade_irq = socrates_fpga_pic_get_irq(irq);
103
104 if (cascade_irq != NO_IRQ)
105 generic_handle_irq(cascade_irq);
106 desc->chip->eoi(irq);
107
108}
109
110static void socrates_fpga_pic_ack(unsigned int virq)
111{
112 unsigned long flags;
113 unsigned int hwirq, irq_line;
114 uint32_t mask;
115
116 hwirq = socrates_fpga_irq_to_hw(virq);
117
118 irq_line = fpga_irqs[hwirq].irq_line;
119 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
120 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
121 & SOCRATES_FPGA_IRQ_MASK;
122 mask |= (1 << (hwirq + 16));
123 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
124 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
125}
126
127static void socrates_fpga_pic_mask(unsigned int virq)
128{
129 unsigned long flags;
130 unsigned int hwirq;
131 int irq_line;
132 u32 mask;
133
134 hwirq = socrates_fpga_irq_to_hw(virq);
135
136 irq_line = fpga_irqs[hwirq].irq_line;
137 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
138 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
139 & SOCRATES_FPGA_IRQ_MASK;
140 mask &= ~(1 << hwirq);
141 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
142 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
143}
144
145static void socrates_fpga_pic_mask_ack(unsigned int virq)
146{
147 unsigned long flags;
148 unsigned int hwirq;
149 int irq_line;
150 u32 mask;
151
152 hwirq = socrates_fpga_irq_to_hw(virq);
153
154 irq_line = fpga_irqs[hwirq].irq_line;
155 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
156 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
157 & SOCRATES_FPGA_IRQ_MASK;
158 mask &= ~(1 << hwirq);
159 mask |= (1 << (hwirq + 16));
160 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
161 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
162}
163
164static void socrates_fpga_pic_unmask(unsigned int virq)
165{
166 unsigned long flags;
167 unsigned int hwirq;
168 int irq_line;
169 u32 mask;
170
171 hwirq = socrates_fpga_irq_to_hw(virq);
172
173 irq_line = fpga_irqs[hwirq].irq_line;
174 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
175 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
176 & SOCRATES_FPGA_IRQ_MASK;
177 mask |= (1 << hwirq);
178 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
179 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
180}
181
182static void socrates_fpga_pic_eoi(unsigned int virq)
183{
184 unsigned long flags;
185 unsigned int hwirq;
186 int irq_line;
187 u32 mask;
188
189 hwirq = socrates_fpga_irq_to_hw(virq);
190
191 irq_line = fpga_irqs[hwirq].irq_line;
192 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
193 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
194 & SOCRATES_FPGA_IRQ_MASK;
195 mask |= (1 << (hwirq + 16));
196 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
197 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
198}
199
200static int socrates_fpga_pic_set_type(unsigned int virq,
201 unsigned int flow_type)
202{
203 unsigned long flags;
204 unsigned int hwirq;
205 int polarity;
206 u32 mask;
207
208 hwirq = socrates_fpga_irq_to_hw(virq);
209
210 if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
211 return -EINVAL;
212
213 switch (flow_type & IRQ_TYPE_SENSE_MASK) {
214 case IRQ_TYPE_LEVEL_HIGH:
215 polarity = 1;
216 break;
217 case IRQ_TYPE_LEVEL_LOW:
218 polarity = 0;
219 break;
220 default:
221 return -EINVAL;
222 }
223 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
224 mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
225 if (polarity)
226 mask |= (1 << hwirq);
227 else
228 mask &= ~(1 << hwirq);
229 socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
230 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
231 return 0;
232}
233
234static struct irq_chip socrates_fpga_pic_chip = {
235 .typename = " FPGA-PIC ",
236 .ack = socrates_fpga_pic_ack,
237 .mask = socrates_fpga_pic_mask,
238 .mask_ack = socrates_fpga_pic_mask_ack,
239 .unmask = socrates_fpga_pic_unmask,
240 .eoi = socrates_fpga_pic_eoi,
241 .set_type = socrates_fpga_pic_set_type,
242};
243
244static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,
245 irq_hw_number_t hwirq)
246{
247 /* All interrupts are LEVEL sensitive */
248 get_irq_desc(virq)->status |= IRQ_LEVEL;
249 set_irq_chip_and_handler(virq, &socrates_fpga_pic_chip,
250 handle_fasteoi_irq);
251
252 return 0;
253}
254
255static int socrates_fpga_pic_host_xlate(struct irq_host *h,
256 struct device_node *ct, u32 *intspec, unsigned int intsize,
257 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
258{
259 struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
260
261 *out_hwirq = intspec[0];
262 if (fpga_irq->type == IRQ_TYPE_NONE) {
263 /* type is configurable */
264 if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
265 intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
266 pr_warning("FPGA PIC: invalid irq type, "
267 "setting default active low\n");
268 *out_flags = IRQ_TYPE_LEVEL_LOW;
269 } else {
270 *out_flags = intspec[1];
271 }
272 } else {
273 /* type is fixed */
274 *out_flags = fpga_irq->type;
275 }
276
277 /* Use specified interrupt routing */
278 if (intspec[2] <= 2)
279 fpga_irq->irq_line = intspec[2];
280 else
281 pr_warning("FPGA PIC: invalid irq routing\n");
282
283 return 0;
284}
285
286static struct irq_host_ops socrates_fpga_pic_host_ops = {
287 .map = socrates_fpga_pic_host_map,
288 .xlate = socrates_fpga_pic_host_xlate,
289};
290
291void socrates_fpga_pic_init(struct device_node *pic)
292{
293 unsigned long flags;
294 int i;
295
296 /* Setup an irq_host structure */
297 socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR,
298 SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops,
299 SOCRATES_FPGA_NUM_IRQS);
300 if (socrates_fpga_pic_irq_host == NULL) {
301 pr_err("FPGA PIC: Unable to allocate host\n");
302 return;
303 }
304
305 for (i = 0; i < 3; i++) {
306 socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
307 if (socrates_fpga_irqs[i] == NO_IRQ) {
308 pr_warning("FPGA PIC: can't get irq%d.\n", i);
309 continue;
310 }
311 set_irq_chained_handler(socrates_fpga_irqs[i],
312 socrates_fpga_pic_cascade);
313 }
314
315 socrates_fpga_pic_iobase = of_iomap(pic, 0);
316
317 spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
318 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
319 SOCRATES_FPGA_IRQ_MASK << 16);
320 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
321 SOCRATES_FPGA_IRQ_MASK << 16);
322 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
323 SOCRATES_FPGA_IRQ_MASK << 16);
324 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
325
326 pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");
327}
diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.h b/arch/powerpc/platforms/85xx/socrates_fpga_pic.h
new file mode 100644
index 000000000000..21d7d8e42199
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.h
@@ -0,0 +1,16 @@
1/*
2 * Copyright (C) 2008 Ilya Yanok, Emcraft Systems
3 *
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 */
10
11#ifndef SOCRATES_FPGA_PIC_H
12#define SOCRATES_FPGA_PIC_H
13
14void socrates_fpga_pic_init(struct device_node *pic);
15
16#endif