aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/52xx
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/52xx')
-rw-r--r--arch/powerpc/platforms/52xx/Makefile9
-rw-r--r--arch/powerpc/platforms/52xx/efika-pci.c119
-rw-r--r--arch/powerpc/platforms/52xx/efika-setup.c150
-rw-r--r--arch/powerpc/platforms/52xx/efika.h19
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c162
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_common.c126
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pic.c473
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pic.h53
8 files changed, 1111 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile
new file mode 100644
index 000000000000..a46184a0c750
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/Makefile
@@ -0,0 +1,9 @@
1#
2# Makefile for 52xx based boards
3#
4ifeq ($(CONFIG_PPC_MERGE),y)
5obj-y += mpc52xx_pic.o mpc52xx_common.o
6endif
7
8obj-$(CONFIG_PPC_EFIKA) += efika-setup.o efika-pci.o
9obj-$(CONFIG_PPC_LITE5200) += lite5200.o
diff --git a/arch/powerpc/platforms/52xx/efika-pci.c b/arch/powerpc/platforms/52xx/efika-pci.c
new file mode 100644
index 000000000000..62e05b2a9227
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/efika-pci.c
@@ -0,0 +1,119 @@
1
2#include <linux/kernel.h>
3#include <linux/pci.h>
4#include <linux/string.h>
5#include <linux/init.h>
6
7#include <asm/io.h>
8#include <asm/irq.h>
9#include <asm/prom.h>
10#include <asm/machdep.h>
11#include <asm/sections.h>
12#include <asm/pci-bridge.h>
13#include <asm/rtas.h>
14
15#include "efika.h"
16
17#ifdef CONFIG_PCI
18/*
19 * Access functions for PCI config space using RTAS calls.
20 */
21static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
22 int len, u32 * val)
23{
24 struct pci_controller *hose = bus->sysdata;
25 unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
26 | (((bus->number - hose->first_busno) & 0xff) << 16)
27 | (hose->index << 24);
28 int ret = -1;
29 int rval;
30
31 rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len);
32 *val = ret;
33 return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
34}
35
36static int rtas_write_config(struct pci_bus *bus, unsigned int devfn,
37 int offset, int len, u32 val)
38{
39 struct pci_controller *hose = bus->sysdata;
40 unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
41 | (((bus->number - hose->first_busno) & 0xff) << 16)
42 | (hose->index << 24);
43 int rval;
44
45 rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL,
46 addr, len, val);
47 return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
48}
49
50static struct pci_ops rtas_pci_ops = {
51 rtas_read_config,
52 rtas_write_config
53};
54
55void __init efika_pcisetup(void)
56{
57 const int *bus_range;
58 int len;
59 struct pci_controller *hose;
60 struct device_node *root;
61 struct device_node *pcictrl;
62
63 root = of_find_node_by_path("/");
64 if (root == NULL) {
65 printk(KERN_WARNING EFIKA_PLATFORM_NAME
66 ": Unable to find the root node\n");
67 return;
68 }
69
70 for (pcictrl = NULL;;) {
71 pcictrl = of_get_next_child(root, pcictrl);
72 if ((pcictrl == NULL) || (strcmp(pcictrl->name, "pci") == 0))
73 break;
74 }
75
76 of_node_put(root);
77
78 if (pcictrl == NULL) {
79 printk(KERN_WARNING EFIKA_PLATFORM_NAME
80 ": Unable to find the PCI bridge node\n");
81 return;
82 }
83
84 bus_range = get_property(pcictrl, "bus-range", &len);
85 if (bus_range == NULL || len < 2 * sizeof(int)) {
86 printk(KERN_WARNING EFIKA_PLATFORM_NAME
87 ": Can't get bus-range for %s\n", pcictrl->full_name);
88 return;
89 }
90
91 if (bus_range[1] == bus_range[0])
92 printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d",
93 bus_range[0]);
94 else
95 printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d",
96 bus_range[0], bus_range[1]);
97 printk(" controlled by %s\n", pcictrl->full_name);
98 printk("\n");
99
100 hose = pcibios_alloc_controller();
101 if (!hose) {
102 printk(KERN_WARNING EFIKA_PLATFORM_NAME
103 ": Can't allocate PCI controller structure for %s\n",
104 pcictrl->full_name);
105 return;
106 }
107
108 hose->arch_data = of_node_get(pcictrl);
109 hose->first_busno = bus_range[0];
110 hose->last_busno = bus_range[1];
111 hose->ops = &rtas_pci_ops;
112
113 pci_process_bridge_OF_ranges(hose, pcictrl, 0);
114}
115
116#else
117void __init efika_pcisetup(void)
118{}
119#endif
diff --git a/arch/powerpc/platforms/52xx/efika-setup.c b/arch/powerpc/platforms/52xx/efika-setup.c
new file mode 100644
index 000000000000..110c980ed1e0
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/efika-setup.c
@@ -0,0 +1,150 @@
1/*
2 *
3 * Efika 5K2 platform setup
4 * Some code really inspired from the lite5200b platform.
5 *
6 * Copyright (C) 2006 bplan GmbH
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 *
12 */
13
14#include <linux/errno.h>
15#include <linux/kernel.h>
16#include <linux/slab.h>
17#include <linux/reboot.h>
18#include <linux/init.h>
19#include <linux/utsrelease.h>
20#include <linux/seq_file.h>
21#include <linux/root_dev.h>
22#include <linux/initrd.h>
23#include <linux/timer.h>
24#include <linux/pci.h>
25
26#include <asm/pgtable.h>
27#include <asm/prom.h>
28#include <asm/time.h>
29#include <asm/machdep.h>
30#include <asm/rtas.h>
31#include <asm/of_device.h>
32#include <asm/of_platform.h>
33#include <asm/mpc52xx.h>
34
35#include "efika.h"
36
37static void efika_show_cpuinfo(struct seq_file *m)
38{
39 struct device_node *root;
40 const char *revision = NULL;
41 const char *codegendescription = NULL;
42 const char *codegenvendor = NULL;
43
44 root = of_find_node_by_path("/");
45 if (root) {
46 revision = get_property(root, "revision", NULL);
47 codegendescription =
48 get_property(root, "CODEGEN,description", NULL);
49 codegenvendor = get_property(root, "CODEGEN,vendor", NULL);
50
51 of_node_put(root);
52 }
53
54 if (codegendescription)
55 seq_printf(m, "machine\t\t: %s\n", codegendescription);
56 else
57 seq_printf(m, "machine\t\t: Efika\n");
58
59 if (revision)
60 seq_printf(m, "revision\t: %s\n", revision);
61
62 if (codegenvendor)
63 seq_printf(m, "vendor\t\t: %s\n", codegenvendor);
64
65 of_node_put(root);
66}
67
68static void __init efika_setup_arch(void)
69{
70 rtas_initialize();
71
72#ifdef CONFIG_BLK_DEV_INITRD
73 initrd_below_start_ok = 1;
74
75 if (initrd_start)
76 ROOT_DEV = Root_RAM0;
77 else
78#endif
79 ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */
80
81 efika_pcisetup();
82
83 if (ppc_md.progress)
84 ppc_md.progress("Linux/PPC " UTS_RELEASE " runnung on Efika ;-)\n", 0x0);
85}
86
87static void __init efika_init(void)
88{
89 struct device_node *np;
90 struct device_node *cnp = NULL;
91 const u32 *base;
92
93 /* Find every child of the SOC node and add it to of_platform */
94 np = of_find_node_by_name(NULL, "builtin");
95 if (np) {
96 char name[BUS_ID_SIZE];
97 while ((cnp = of_get_next_child(np, cnp))) {
98 strcpy(name, cnp->name);
99
100 base = get_property(cnp, "reg", NULL);
101 if (base == NULL)
102 continue;
103
104 snprintf(name+strlen(name), BUS_ID_SIZE, "@%x", *base);
105 of_platform_device_create(cnp, name, NULL);
106
107 printk(KERN_INFO EFIKA_PLATFORM_NAME" : Added %s (type '%s' at '%s') to the known devices\n", name, cnp->type, cnp->full_name);
108 }
109 }
110
111 if (ppc_md.progress)
112 ppc_md.progress(" Have fun with your Efika! ", 0x7777);
113}
114
115static int __init efika_probe(void)
116{
117 char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
118 "model", NULL);
119
120 if (model == NULL)
121 return 0;
122 if (strcmp(model, "EFIKA5K2"))
123 return 0;
124
125 ISA_DMA_THRESHOLD = ~0L;
126 DMA_MODE_READ = 0x44;
127 DMA_MODE_WRITE = 0x48;
128
129 return 1;
130}
131
132define_machine(efika)
133{
134 .name = EFIKA_PLATFORM_NAME,
135 .probe = efika_probe,
136 .setup_arch = efika_setup_arch,
137 .init = efika_init,
138 .show_cpuinfo = efika_show_cpuinfo,
139 .init_IRQ = mpc52xx_init_irq,
140 .get_irq = mpc52xx_get_irq,
141 .restart = rtas_restart,
142 .power_off = rtas_power_off,
143 .halt = rtas_halt,
144 .set_rtc_time = rtas_set_rtc_time,
145 .get_rtc_time = rtas_get_rtc_time,
146 .progress = rtas_progress,
147 .get_boot_time = rtas_get_boot_time,
148 .calibrate_decr = generic_calibrate_decr,
149 .phys_mem_access_prot = pci_phys_mem_access_prot,
150};
diff --git a/arch/powerpc/platforms/52xx/efika.h b/arch/powerpc/platforms/52xx/efika.h
new file mode 100644
index 000000000000..2f060fd097d7
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/efika.h
@@ -0,0 +1,19 @@
1/*
2 * Efika 5K2 platform setup - Header file
3 *
4 * Copyright (C) 2006 bplan GmbH
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 *
10 */
11
12#ifndef __ARCH_POWERPC_EFIKA__
13#define __ARCH_POWERPC_EFIKA__
14
15#define EFIKA_PLATFORM_NAME "Efika"
16
17extern void __init efika_pcisetup(void);
18
19#endif
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
new file mode 100644
index 000000000000..a375c15b4315
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -0,0 +1,162 @@
1/*
2 * Freescale Lite5200 board support
3 *
4 * Written by: Grant Likely <grant.likely@secretlab.ca>
5 *
6 * Copyright (C) Secret Lab Technologies Ltd. 2006. All rights reserved.
7 * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
8 *
9 * Description:
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#undef DEBUG
17
18#include <linux/stddef.h>
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/errno.h>
22#include <linux/reboot.h>
23#include <linux/pci.h>
24#include <linux/kdev_t.h>
25#include <linux/major.h>
26#include <linux/console.h>
27#include <linux/delay.h>
28#include <linux/seq_file.h>
29#include <linux/root_dev.h>
30#include <linux/initrd.h>
31
32#include <asm/system.h>
33#include <asm/atomic.h>
34#include <asm/time.h>
35#include <asm/io.h>
36#include <asm/machdep.h>
37#include <asm/ipic.h>
38#include <asm/bootinfo.h>
39#include <asm/irq.h>
40#include <asm/prom.h>
41#include <asm/udbg.h>
42#include <sysdev/fsl_soc.h>
43#include <asm/qe.h>
44#include <asm/qe_ic.h>
45#include <asm/of_platform.h>
46
47#include <asm/mpc52xx.h>
48
49/* ************************************************************************
50 *
51 * Setup the architecture
52 *
53 */
54
55static void __init
56lite52xx_setup_cpu(void)
57{
58 struct mpc52xx_gpio __iomem *gpio;
59 u32 port_config;
60
61 /* Map zones */
62 gpio = mpc52xx_find_and_map("mpc52xx-gpio");
63 if (!gpio) {
64 printk(KERN_ERR __FILE__ ": "
65 "Error while mapping GPIO register for port config. "
66 "Expect some abnormal behavior\n");
67 goto error;
68 }
69
70 /* Set port config */
71 port_config = in_be32(&gpio->port_config);
72
73 port_config &= ~0x00800000; /* 48Mhz internal, pin is GPIO */
74
75 port_config &= ~0x00007000; /* USB port : Differential mode */
76 port_config |= 0x00001000; /* USB 1 only */
77
78 port_config &= ~0x03000000; /* ATA CS is on csb_4/5 */
79 port_config |= 0x01000000;
80
81 pr_debug("port_config: old:%x new:%x\n",
82 in_be32(&gpio->port_config), port_config);
83 out_be32(&gpio->port_config, port_config);
84
85 /* Unmap zone */
86error:
87 iounmap(gpio);
88}
89
90static void __init lite52xx_setup_arch(void)
91{
92 struct device_node *np;
93
94 if (ppc_md.progress)
95 ppc_md.progress("lite52xx_setup_arch()", 0);
96
97 np = of_find_node_by_type(NULL, "cpu");
98 if (np) {
99 unsigned int *fp =
100 (int *)get_property(np, "clock-frequency", NULL);
101 if (fp != 0)
102 loops_per_jiffy = *fp / HZ;
103 else
104 loops_per_jiffy = 50000000 / HZ;
105 of_node_put(np);
106 }
107
108 /* CPU & Port mux setup */
109 mpc52xx_setup_cpu(); /* Generic */
110 lite52xx_setup_cpu(); /* Platorm specific */
111
112#ifdef CONFIG_BLK_DEV_INITRD
113 if (initrd_start)
114 ROOT_DEV = Root_RAM0;
115 else
116#endif
117#ifdef CONFIG_ROOT_NFS
118 ROOT_DEV = Root_NFS;
119#else
120 ROOT_DEV = Root_HDA1;
121#endif
122
123}
124
125void lite52xx_show_cpuinfo(struct seq_file *m)
126{
127 struct device_node* np = of_find_all_nodes(NULL);
128 const char *model = NULL;
129
130 if (np)
131 model = get_property(np, "model", NULL);
132
133 seq_printf(m, "vendor\t\t: Freescale Semiconductor\n");
134 seq_printf(m, "machine\t\t: %s\n", model ? model : "unknown");
135
136 of_node_put(np);
137}
138
139/*
140 * Called very early, MMU is off, device-tree isn't unflattened
141 */
142static int __init lite52xx_probe(void)
143{
144 unsigned long node = of_get_flat_dt_root();
145 const char *model = of_get_flat_dt_prop(node, "model", NULL);
146
147 if (!of_flat_dt_is_compatible(node, "lite52xx"))
148 return 0;
149 pr_debug("%s board w/ mpc52xx found\n", model ? model : "unknown");
150
151 return 1;
152}
153
154define_machine(lite52xx) {
155 .name = "lite52xx",
156 .probe = lite52xx_probe,
157 .setup_arch = lite52xx_setup_arch,
158 .init_IRQ = mpc52xx_init_irq,
159 .get_irq = mpc52xx_get_irq,
160 .show_cpuinfo = lite52xx_show_cpuinfo,
161 .calibrate_decr = generic_calibrate_decr,
162};
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c
new file mode 100644
index 000000000000..8331ff457770
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -0,0 +1,126 @@
1/*
2 *
3 * Utility functions for the Freescale MPC52xx.
4 *
5 * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
6 *
7 * This file is licensed under the terms of the GNU General Public License
8 * version 2. This program is licensed "as is" without any warranty of any
9 * kind, whether express or implied.
10 *
11 */
12
13#undef DEBUG
14
15#include <linux/kernel.h>
16
17#include <asm/io.h>
18#include <asm/prom.h>
19#include <asm/of_platform.h>
20#include <asm/mpc52xx.h>
21
22
23void __iomem *
24mpc52xx_find_and_map(const char *compatible)
25{
26 struct device_node *ofn;
27 const u32 *regaddr_p;
28 u64 regaddr64, size64;
29
30 ofn = of_find_compatible_node(NULL, NULL, compatible);
31 if (!ofn)
32 return NULL;
33
34 regaddr_p = of_get_address(ofn, 0, &size64, NULL);
35 if (!regaddr_p) {
36 of_node_put(ofn);
37 return NULL;
38 }
39
40 regaddr64 = of_translate_address(ofn, regaddr_p);
41
42 of_node_put(ofn);
43
44 return ioremap((u32)regaddr64, (u32)size64);
45}
46EXPORT_SYMBOL(mpc52xx_find_and_map);
47
48
49/**
50 * mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device
51 * @node: device node
52 *
53 * Returns IPB bus frequency, or 0 if the bus frequency cannot be found.
54 */
55unsigned int
56mpc52xx_find_ipb_freq(struct device_node *node)
57{
58 struct device_node *np;
59 const unsigned int *p_ipb_freq = NULL;
60
61 of_node_get(node);
62 while (node) {
63 p_ipb_freq = get_property(node, "bus-frequency", NULL);
64 if (p_ipb_freq)
65 break;
66
67 np = of_get_parent(node);
68 of_node_put(node);
69 node = np;
70 }
71 if (node)
72 of_node_put(node);
73
74 return p_ipb_freq ? *p_ipb_freq : 0;
75}
76EXPORT_SYMBOL(mpc52xx_find_ipb_freq);
77
78
79void __init
80mpc52xx_setup_cpu(void)
81{
82 struct mpc52xx_cdm __iomem *cdm;
83 struct mpc52xx_xlb __iomem *xlb;
84
85 /* Map zones */
86 cdm = mpc52xx_find_and_map("mpc52xx-cdm");
87 xlb = mpc52xx_find_and_map("mpc52xx-xlb");
88
89 if (!cdm || !xlb) {
90 printk(KERN_ERR __FILE__ ": "
91 "Error while mapping CDM/XLB during mpc52xx_setup_cpu. "
92 "Expect some abnormal behavior\n");
93 goto unmap_regs;
94 }
95
96 /* Use internal 48 Mhz */
97 out_8(&cdm->ext_48mhz_en, 0x00);
98 out_8(&cdm->fd_enable, 0x01);
99 if (in_be32(&cdm->rstcfg) & 0x40) /* Assumes 33Mhz clock */
100 out_be16(&cdm->fd_counters, 0x0001);
101 else
102 out_be16(&cdm->fd_counters, 0x5555);
103
104 /* Configure the XLB Arbiter priorities */
105 out_be32(&xlb->master_pri_enable, 0xff);
106 out_be32(&xlb->master_priority, 0x11111111);
107
108 /* Disable XLB pipelining */
109 /* (cfr errate 292. We could do this only just before ATA PIO
110 transaction and re-enable it afterwards ...) */
111 out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS);
112
113 /* Unmap zones */
114unmap_regs:
115 if (cdm) iounmap(cdm);
116 if (xlb) iounmap(xlb);
117}
118
119static int __init
120mpc52xx_declare_of_platform_devices(void)
121{
122 /* Find every child of the SOC node and add it to of_platform */
123 return of_platform_bus_probe(NULL, NULL, NULL);
124}
125
126device_initcall(mpc52xx_declare_of_platform_devices);
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
new file mode 100644
index 000000000000..cd91a6c3aafa
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
@@ -0,0 +1,473 @@
1/*
2 *
3 * Programmable Interrupt Controller functions for the Freescale MPC52xx.
4 *
5 * Copyright (C) 2006 bplan GmbH
6 *
7 * Based on the code from the 2.4 kernel by
8 * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
9 *
10 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
11 * Copyright (C) 2003 Montavista Software, Inc
12 *
13 * This file is licensed under the terms of the GNU General Public License
14 * version 2. This program is licensed "as is" without any warranty of any
15 * kind, whether express or implied.
16 *
17 */
18
19#undef DEBUG
20
21#include <linux/stddef.h>
22#include <linux/init.h>
23#include <linux/sched.h>
24#include <linux/signal.h>
25#include <linux/stddef.h>
26#include <linux/delay.h>
27#include <linux/irq.h>
28#include <linux/hardirq.h>
29
30#include <asm/io.h>
31#include <asm/processor.h>
32#include <asm/system.h>
33#include <asm/irq.h>
34#include <asm/prom.h>
35#include <asm/mpc52xx.h>
36#include "mpc52xx_pic.h"
37
38/*
39 *
40*/
41
42static struct mpc52xx_intr __iomem *intr;
43static struct mpc52xx_sdma __iomem *sdma;
44static struct irq_host *mpc52xx_irqhost = NULL;
45
46static unsigned char mpc52xx_map_senses[4] = {
47 IRQ_TYPE_LEVEL_HIGH,
48 IRQ_TYPE_EDGE_RISING,
49 IRQ_TYPE_EDGE_FALLING,
50 IRQ_TYPE_LEVEL_LOW,
51};
52
53/*
54 *
55*/
56
57static inline void io_be_setbit(u32 __iomem *addr, int bitno)
58{
59 out_be32(addr, in_be32(addr) | (1 << bitno));
60}
61
62static inline void io_be_clrbit(u32 __iomem *addr, int bitno)
63{
64 out_be32(addr, in_be32(addr) & ~(1 << bitno));
65}
66
67/*
68 * IRQ[0-3] interrupt irq_chip
69*/
70
71static void mpc52xx_extirq_mask(unsigned int virq)
72{
73 int irq;
74 int l2irq;
75
76 irq = irq_map[virq].hwirq;
77 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
78
79 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
80
81 io_be_clrbit(&intr->ctrl, 11 - l2irq);
82}
83
84static void mpc52xx_extirq_unmask(unsigned int virq)
85{
86 int irq;
87 int l2irq;
88
89 irq = irq_map[virq].hwirq;
90 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
91
92 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
93
94 io_be_setbit(&intr->ctrl, 11 - l2irq);
95}
96
97static void mpc52xx_extirq_ack(unsigned int virq)
98{
99 int irq;
100 int l2irq;
101
102 irq = irq_map[virq].hwirq;
103 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
104
105 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
106
107 io_be_setbit(&intr->ctrl, 27-l2irq);
108}
109
110static struct irq_chip mpc52xx_extirq_irqchip = {
111 .typename = " MPC52xx IRQ[0-3] ",
112 .mask = mpc52xx_extirq_mask,
113 .unmask = mpc52xx_extirq_unmask,
114 .ack = mpc52xx_extirq_ack,
115};
116
117/*
118 * Main interrupt irq_chip
119*/
120
121static void mpc52xx_main_mask(unsigned int virq)
122{
123 int irq;
124 int l2irq;
125
126 irq = irq_map[virq].hwirq;
127 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
128
129 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
130
131 io_be_setbit(&intr->main_mask, 15 - l2irq);
132}
133
134static void mpc52xx_main_unmask(unsigned int virq)
135{
136 int irq;
137 int l2irq;
138
139 irq = irq_map[virq].hwirq;
140 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
141
142 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
143
144 io_be_clrbit(&intr->main_mask, 15 - l2irq);
145}
146
147static struct irq_chip mpc52xx_main_irqchip = {
148 .typename = "MPC52xx Main",
149 .mask = mpc52xx_main_mask,
150 .mask_ack = mpc52xx_main_mask,
151 .unmask = mpc52xx_main_unmask,
152};
153
154/*
155 * Peripherals interrupt irq_chip
156*/
157
158static void mpc52xx_periph_mask(unsigned int virq)
159{
160 int irq;
161 int l2irq;
162
163 irq = irq_map[virq].hwirq;
164 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
165
166 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
167
168 io_be_setbit(&intr->per_mask, 31 - l2irq);
169}
170
171static void mpc52xx_periph_unmask(unsigned int virq)
172{
173 int irq;
174 int l2irq;
175
176 irq = irq_map[virq].hwirq;
177 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
178
179 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
180
181 io_be_clrbit(&intr->per_mask, 31 - l2irq);
182}
183
184static struct irq_chip mpc52xx_periph_irqchip = {
185 .typename = "MPC52xx Peripherals",
186 .mask = mpc52xx_periph_mask,
187 .mask_ack = mpc52xx_periph_mask,
188 .unmask = mpc52xx_periph_unmask,
189};
190
191/*
192 * SDMA interrupt irq_chip
193*/
194
195static void mpc52xx_sdma_mask(unsigned int virq)
196{
197 int irq;
198 int l2irq;
199
200 irq = irq_map[virq].hwirq;
201 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
202
203 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
204
205 io_be_setbit(&sdma->IntMask, l2irq);
206}
207
208static void mpc52xx_sdma_unmask(unsigned int virq)
209{
210 int irq;
211 int l2irq;
212
213 irq = irq_map[virq].hwirq;
214 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
215
216 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
217
218 io_be_clrbit(&sdma->IntMask, l2irq);
219}
220
221static void mpc52xx_sdma_ack(unsigned int virq)
222{
223 int irq;
224 int l2irq;
225
226 irq = irq_map[virq].hwirq;
227 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
228
229 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
230
231 out_be32(&sdma->IntPend, 1 << l2irq);
232}
233
234static struct irq_chip mpc52xx_sdma_irqchip = {
235 .typename = "MPC52xx SDMA",
236 .mask = mpc52xx_sdma_mask,
237 .unmask = mpc52xx_sdma_unmask,
238 .ack = mpc52xx_sdma_ack,
239};
240
241/*
242 * irq_host
243*/
244
245static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node)
246{
247 pr_debug("%s: node=%p\n", __func__, node);
248 return mpc52xx_irqhost->host_data == node;
249}
250
251static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
252 u32 * intspec, unsigned int intsize,
253 irq_hw_number_t * out_hwirq,
254 unsigned int *out_flags)
255{
256 int intrvect_l1;
257 int intrvect_l2;
258 int intrvect_type;
259 int intrvect_linux;
260
261 if (intsize != 3)
262 return -1;
263
264 intrvect_l1 = (int)intspec[0];
265 intrvect_l2 = (int)intspec[1];
266 intrvect_type = (int)intspec[2];
267
268 intrvect_linux =
269 (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK;
270 intrvect_linux |=
271 (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK;
272
273 pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
274 intrvect_l2);
275
276 *out_hwirq = intrvect_linux;
277 *out_flags = mpc52xx_map_senses[intrvect_type];
278
279 return 0;
280}
281
282/*
283 * this function retrieves the correct IRQ type out
284 * of the MPC regs
285 * Only externals IRQs needs this
286*/
287static int mpc52xx_irqx_gettype(int irq)
288{
289 int type;
290 u32 ctrl_reg;
291
292 ctrl_reg = in_be32(&intr->ctrl);
293 type = (ctrl_reg >> (22 - irq * 2)) & 0x3;
294
295 return mpc52xx_map_senses[type];
296}
297
298static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
299 irq_hw_number_t irq)
300{
301 int l1irq;
302 int l2irq;
303 struct irq_chip *good_irqchip;
304 void *good_handle;
305 int type;
306
307 l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
308 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
309
310 /*
311 * Most of ours IRQs will be level low
312 * Only external IRQs on some platform may be others
313 */
314 type = IRQ_TYPE_LEVEL_LOW;
315
316 switch (l1irq) {
317 case MPC52xx_IRQ_L1_CRIT:
318 pr_debug("%s: Critical. l2=%x\n", __func__, l2irq);
319
320 BUG_ON(l2irq != 0);
321
322 type = mpc52xx_irqx_gettype(l2irq);
323 good_irqchip = &mpc52xx_extirq_irqchip;
324 break;
325
326 case MPC52xx_IRQ_L1_MAIN:
327 pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq);
328
329 if ((l2irq >= 1) && (l2irq <= 3)) {
330 type = mpc52xx_irqx_gettype(l2irq);
331 good_irqchip = &mpc52xx_extirq_irqchip;
332 } else {
333 good_irqchip = &mpc52xx_main_irqchip;
334 }
335 break;
336
337 case MPC52xx_IRQ_L1_PERP:
338 pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq);
339 good_irqchip = &mpc52xx_periph_irqchip;
340 break;
341
342 case MPC52xx_IRQ_L1_SDMA:
343 pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq);
344 good_irqchip = &mpc52xx_sdma_irqchip;
345 break;
346
347 default:
348 pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq);
349 printk(KERN_ERR "Unknow IRQ!\n");
350 return -EINVAL;
351 }
352
353 switch (type) {
354 case IRQ_TYPE_EDGE_FALLING:
355 case IRQ_TYPE_EDGE_RISING:
356 good_handle = handle_edge_irq;
357 break;
358 default:
359 good_handle = handle_level_irq;
360 }
361
362 set_irq_chip_and_handler(virq, good_irqchip, good_handle);
363
364 pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq,
365 (int)irq, type);
366
367 return 0;
368}
369
370static struct irq_host_ops mpc52xx_irqhost_ops = {
371 .match = mpc52xx_irqhost_match,
372 .xlate = mpc52xx_irqhost_xlate,
373 .map = mpc52xx_irqhost_map,
374};
375
376/*
377 * init (public)
378*/
379
380void __init mpc52xx_init_irq(void)
381{
382 u32 intr_ctrl;
383 struct device_node *picnode;
384
385 /* Remap the necessary zones */
386 picnode = of_find_compatible_node(NULL, NULL, "mpc52xx-pic");
387
388 intr = mpc52xx_find_and_map("mpc52xx-pic");
389 if (!intr)
390 panic(__FILE__ ": find_and_map failed on 'mpc52xx-pic'. "
391 "Check node !");
392
393 sdma = mpc52xx_find_and_map("mpc52xx-bestcomm");
394 if (!sdma)
395 panic(__FILE__ ": find_and_map failed on 'mpc52xx-bestcomm'. "
396 "Check node !");
397
398 /* Disable all interrupt sources. */
399 out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */
400 out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */
401 out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */
402 out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
403 intr_ctrl = in_be32(&intr->ctrl);
404 intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */
405 intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */
406 0x00001000 | /* MEE master external enable */
407 0x00000000 | /* 0 means disable IRQ 0-3 */
408 0x00000001; /* CEb route critical normally */
409 out_be32(&intr->ctrl, intr_ctrl);
410
411 /* Zero a bunch of the priority settings. */
412 out_be32(&intr->per_pri1, 0);
413 out_be32(&intr->per_pri2, 0);
414 out_be32(&intr->per_pri3, 0);
415 out_be32(&intr->main_pri1, 0);
416 out_be32(&intr->main_pri2, 0);
417
418 /*
419 * As last step, add an irq host to translate the real
420 * hw irq information provided by the ofw to linux virq
421 */
422
423 mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
424 MPC52xx_IRQ_HIGHTESTHWIRQ,
425 &mpc52xx_irqhost_ops, -1);
426
427 if (!mpc52xx_irqhost)
428 panic(__FILE__ ": Cannot allocate the IRQ host\n");
429
430 mpc52xx_irqhost->host_data = picnode;
431 printk(KERN_INFO "MPC52xx PIC is up and running!\n");
432}
433
434/*
435 * get_irq (public)
436*/
437unsigned int mpc52xx_get_irq(void)
438{
439 u32 status;
440 int irq = NO_IRQ_IGNORE;
441
442 status = in_be32(&intr->enc_status);
443 if (status & 0x00000400) { /* critical */
444 irq = (status >> 8) & 0x3;
445 if (irq == 2) /* high priority peripheral */
446 goto peripheral;
447 irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) &
448 MPC52xx_IRQ_L1_MASK;
449 } else if (status & 0x00200000) { /* main */
450 irq = (status >> 16) & 0x1f;
451 if (irq == 4) /* low priority peripheral */
452 goto peripheral;
453 irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) &
454 MPC52xx_IRQ_L1_MASK;
455 } else if (status & 0x20000000) { /* peripheral */
456 peripheral:
457 irq = (status >> 24) & 0x1f;
458 if (irq == 0) { /* bestcomm */
459 status = in_be32(&sdma->IntPend);
460 irq = ffs(status) - 1;
461 irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) &
462 MPC52xx_IRQ_L1_MASK;
463 } else {
464 irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) &
465 MPC52xx_IRQ_L1_MASK;
466 }
467 }
468
469 pr_debug("%s: irq=%x. virq=%d\n", __func__, irq,
470 irq_linear_revmap(mpc52xx_irqhost, irq));
471
472 return irq_linear_revmap(mpc52xx_irqhost, irq);
473}
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.h b/arch/powerpc/platforms/52xx/mpc52xx_pic.h
new file mode 100644
index 000000000000..1a26bcdb3049
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.h
@@ -0,0 +1,53 @@
1/*
2 * Header file for Freescale MPC52xx Interrupt controller
3 *
4 * Copyright (C) 2004-2005 Sylvain Munaut <tnt@246tNt.com>
5 * Copyright (C) 2003 MontaVista, Software, Inc.
6 *
7 * This file is licensed under the terms of the GNU General Public License
8 * version 2. This program is licensed "as is" without any warranty of any
9 * kind, whether express or implied.
10 */
11
12#ifndef __POWERPC_SYSDEV_MPC52xx_PIC_H__
13#define __POWERPC_SYSDEV_MPC52xx_PIC_H__
14
15#include <asm/types.h>
16
17
18/* HW IRQ mapping */
19#define MPC52xx_IRQ_L1_CRIT (0)
20#define MPC52xx_IRQ_L1_MAIN (1)
21#define MPC52xx_IRQ_L1_PERP (2)
22#define MPC52xx_IRQ_L1_SDMA (3)
23
24#define MPC52xx_IRQ_L1_OFFSET (6)
25#define MPC52xx_IRQ_L1_MASK (0x00c0)
26
27#define MPC52xx_IRQ_L2_OFFSET (0)
28#define MPC52xx_IRQ_L2_MASK (0x003f)
29
30#define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0)
31
32
33/* Interrupt controller Register set */
34struct mpc52xx_intr {
35 u32 per_mask; /* INTR + 0x00 */
36 u32 per_pri1; /* INTR + 0x04 */
37 u32 per_pri2; /* INTR + 0x08 */
38 u32 per_pri3; /* INTR + 0x0c */
39 u32 ctrl; /* INTR + 0x10 */
40 u32 main_mask; /* INTR + 0x14 */
41 u32 main_pri1; /* INTR + 0x18 */
42 u32 main_pri2; /* INTR + 0x1c */
43 u32 reserved1; /* INTR + 0x20 */
44 u32 enc_status; /* INTR + 0x24 */
45 u32 crit_status; /* INTR + 0x28 */
46 u32 main_status; /* INTR + 0x2c */
47 u32 per_status; /* INTR + 0x30 */
48 u32 reserved2; /* INTR + 0x34 */
49 u32 per_error; /* INTR + 0x38 */
50};
51
52#endif /* __POWERPC_SYSDEV_MPC52xx_PIC_H__ */
53