aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/lib/Makefile5
-rw-r--r--arch/powerpc/sysdev/Makefile5
-rw-r--r--arch/powerpc/sysdev/cpm2_common.c210
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.c256
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.h8
-rw-r--r--include/asm-ppc/cpm2.h6
6 files changed, 489 insertions, 1 deletions
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 336dd191f768..8030f6245d82 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -20,3 +20,8 @@ ifeq ($(CONFIG_PPC64),y)
20obj-$(CONFIG_SMP) += locks.o 20obj-$(CONFIG_SMP) += locks.o
21obj-$(CONFIG_DEBUG_KERNEL) += sstep.o 21obj-$(CONFIG_DEBUG_KERNEL) += sstep.o
22endif 22endif
23
24# Temporary hack until we have migrated to asm-powerpc
25ifeq ($(CONFIG_PPC_MERGE),y)
26obj-$(CONFIG_CPM2) += rheap.o
27endif
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index e5e999ea891a..f15f4d78aee9 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -17,3 +17,8 @@ ifeq ($(CONFIG_PPC_MERGE),y)
17obj-$(CONFIG_PPC_I8259) += i8259.o 17obj-$(CONFIG_PPC_I8259) += i8259.o
18obj-$(CONFIG_PPC_83xx) += ipic.o 18obj-$(CONFIG_PPC_83xx) += ipic.o
19endif 19endif
20
21# Temporary hack until we have migrated to asm-powerpc
22ifeq ($(ARCH),powerpc)
23obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o
24endif
diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c
new file mode 100644
index 000000000000..f7a04892400b
--- /dev/null
+++ b/arch/powerpc/sysdev/cpm2_common.c
@@ -0,0 +1,210 @@
1/*
2 * General Purpose functions for the global management of the
3 * 8260 Communication Processor Module.
4 * Copyright (c) 1999-2001 Dan Malek <dan@embeddedalley.com>
5 * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
6 * 2.3.99 Updates
7 *
8 * 2006 (c) MontaVista Software, Inc.
9 * Vitaly Bordug <vbordug@ru.mvista.com>
10 * Merged to arch/powerpc from arch/ppc/syslib/cpm2_common.c
11 *
12 * This file is licensed under the terms of the GNU General Public License
13 * version 2. This program is licensed "as is" without any warranty of any
14 * kind, whether express or implied.
15 */
16
17/*
18 *
19 * In addition to the individual control of the communication
20 * channels, there are a few functions that globally affect the
21 * communication processor.
22 *
23 * Buffer descriptors must be allocated from the dual ported memory
24 * space. The allocator for that is here. When the communication
25 * process is reset, we reclaim the memory available. There is
26 * currently no deallocator for this memory.
27 */
28#include <linux/errno.h>
29#include <linux/sched.h>
30#include <linux/kernel.h>
31#include <linux/param.h>
32#include <linux/string.h>
33#include <linux/mm.h>
34#include <linux/interrupt.h>
35#include <linux/module.h>
36#include <asm/io.h>
37#include <asm/irq.h>
38#include <asm/mpc8260.h>
39#include <asm/page.h>
40#include <asm/pgtable.h>
41#include <asm/cpm2.h>
42#include <asm/rheap.h>
43#include <asm/fs_pd.h>
44
45#include <sysdev/fsl_soc.h>
46
47static void cpm2_dpinit(void);
48cpm_cpm2_t *cpmp; /* Pointer to comm processor space */
49
50/* We allocate this here because it is used almost exclusively for
51 * the communication processor devices.
52 */
53cpm2_map_t *cpm2_immr;
54
55#define CPM_MAP_SIZE (0x40000) /* 256k - the PQ3 reserve this amount
56 of space for CPM as it is larger
57 than on PQ2 */
58
59void
60cpm2_reset(void)
61{
62 cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
63
64 /* Reclaim the DP memory for our use.
65 */
66 cpm2_dpinit();
67
68 /* Tell everyone where the comm processor resides.
69 */
70 cpmp = &cpm2_immr->im_cpm;
71}
72
73/* Set a baud rate generator. This needs lots of work. There are
74 * eight BRGs, which can be connected to the CPM channels or output
75 * as clocks. The BRGs are in two different block of internal
76 * memory mapped space.
77 * The baud rate clock is the system clock divided by something.
78 * It was set up long ago during the initial boot phase and is
79 * is given to us.
80 * Baud rate clocks are zero-based in the driver code (as that maps
81 * to port numbers). Documentation uses 1-based numbering.
82 */
83#define BRG_INT_CLK (get_brgfreq())
84#define BRG_UART_CLK (BRG_INT_CLK/16)
85
86/* This function is used by UARTS, or anything else that uses a 16x
87 * oversampled clock.
88 */
89void
90cpm_setbrg(uint brg, uint rate)
91{
92 volatile uint *bp;
93
94 /* This is good enough to get SMCs running.....
95 */
96 if (brg < 4) {
97 bp = (uint *)&cpm2_immr->im_brgc1;
98 } else {
99 bp = (uint *)&cpm2_immr->im_brgc5;
100 brg -= 4;
101 }
102 bp += brg;
103 *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
104}
105
106/* This function is used to set high speed synchronous baud rate
107 * clocks.
108 */
109void
110cpm2_fastbrg(uint brg, uint rate, int div16)
111{
112 volatile uint *bp;
113
114 if (brg < 4) {
115 bp = (uint *)&cpm2_immr->im_brgc1;
116 }
117 else {
118 bp = (uint *)&cpm2_immr->im_brgc5;
119 brg -= 4;
120 }
121 bp += brg;
122 *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
123 if (div16)
124 *bp |= CPM_BRG_DIV16;
125}
126
127/*
128 * dpalloc / dpfree bits.
129 */
130static spinlock_t cpm_dpmem_lock;
131/* 16 blocks should be enough to satisfy all requests
132 * until the memory subsystem goes up... */
133static rh_block_t cpm_boot_dpmem_rh_block[16];
134static rh_info_t cpm_dpmem_info;
135
136static void cpm2_dpinit(void)
137{
138 spin_lock_init(&cpm_dpmem_lock);
139
140 /* initialize the info header */
141 rh_init(&cpm_dpmem_info, 1,
142 sizeof(cpm_boot_dpmem_rh_block) /
143 sizeof(cpm_boot_dpmem_rh_block[0]),
144 cpm_boot_dpmem_rh_block);
145
146 /* Attach the usable dpmem area */
147 /* XXX: This is actually crap. CPM_DATAONLY_BASE and
148 * CPM_DATAONLY_SIZE is only a subset of the available dpram. It
149 * varies with the processor and the microcode patches activated.
150 * But the following should be at least safe.
151 */
152 rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE,
153 CPM_DATAONLY_SIZE);
154}
155
156/* This function returns an index into the DPRAM area.
157 */
158uint cpm_dpalloc(uint size, uint align)
159{
160 void *start;
161 unsigned long flags;
162
163 spin_lock_irqsave(&cpm_dpmem_lock, flags);
164 cpm_dpmem_info.alignment = align;
165 start = rh_alloc(&cpm_dpmem_info, size, "commproc");
166 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
167
168 return (uint)start;
169}
170EXPORT_SYMBOL(cpm_dpalloc);
171
172int cpm_dpfree(uint offset)
173{
174 int ret;
175 unsigned long flags;
176
177 spin_lock_irqsave(&cpm_dpmem_lock, flags);
178 ret = rh_free(&cpm_dpmem_info, (void *)offset);
179 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
180
181 return ret;
182}
183EXPORT_SYMBOL(cpm_dpfree);
184
185/* not sure if this is ever needed */
186uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
187{
188 void *start;
189 unsigned long flags;
190
191 spin_lock_irqsave(&cpm_dpmem_lock, flags);
192 cpm_dpmem_info.alignment = align;
193 start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
194 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
195
196 return (uint)start;
197}
198EXPORT_SYMBOL(cpm_dpalloc_fixed);
199
200void cpm_dpdump(void)
201{
202 rh_dump(&cpm_dpmem_info);
203}
204EXPORT_SYMBOL(cpm_dpdump);
205
206void *cpm_dpram_addr(uint offset)
207{
208 return (void *)&cpm2_immr->im_dprambase[offset];
209}
210EXPORT_SYMBOL(cpm_dpram_addr);
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
new file mode 100644
index 000000000000..c804475c07d3
--- /dev/null
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -0,0 +1,256 @@
1/*
2 * Platform information definitions.
3 *
4 * Copied from arch/ppc/syslib/cpm2_pic.c with minor subsequent updates
5 * to make in work in arch/powerpc/. Original (c) belongs to Dan Malek.
6 *
7 * Author: Vitaly Bordug <vbordug@ru.mvista.com>
8 *
9 * 1999-2001 (c) Dan Malek <dan@embeddedalley.com>
10 * 2006 (c) MontaVista Software, Inc.
11 *
12 * This file is licensed under the terms of the GNU General Public License
13 * version 2. This program is licensed "as is" without any warranty of any
14 * kind, whether express or implied.
15 */
16
17/* The CPM2 internal interrupt controller. It is usually
18 * the only interrupt controller.
19 * There are two 32-bit registers (high/low) for up to 64
20 * possible interrupts.
21 *
22 * Now, the fun starts.....Interrupt Numbers DO NOT MAP
23 * in a simple arithmetic fashion to mask or pending registers.
24 * That is, interrupt 4 does not map to bit position 4.
25 * We create two tables, indexed by vector number, to indicate
26 * which register to use and which bit in the register to use.
27 */
28
29#include <linux/stddef.h>
30#include <linux/init.h>
31#include <linux/sched.h>
32#include <linux/signal.h>
33#include <linux/irq.h>
34
35#include <asm/immap_cpm2.h>
36#include <asm/mpc8260.h>
37#include <asm/io.h>
38#include <asm/prom.h>
39
40#include "cpm2_pic.h"
41
42static struct device_node *cpm2_pic_node;
43static struct irq_host *cpm2_pic_host;
44#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
45static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
46
47static const u_char irq_to_siureg[] = {
48 1, 1, 1, 1, 1, 1, 1, 1,
49 1, 1, 1, 1, 1, 1, 1, 1,
50 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0,
52 1, 1, 1, 1, 1, 1, 1, 1,
53 1, 1, 1, 1, 1, 1, 1, 1,
54 0, 0, 0, 0, 0, 0, 0, 0,
55 0, 0, 0, 0, 0, 0, 0, 0
56};
57
58/* bit numbers do not match the docs, these are precomputed so the bit for
59 * a given irq is (1 << irq_to_siubit[irq]) */
60static const u_char irq_to_siubit[] = {
61 0, 15, 14, 13, 12, 11, 10, 9,
62 8, 7, 6, 5, 4, 3, 2, 1,
63 2, 1, 0, 14, 13, 12, 11, 10,
64 9, 8, 7, 6, 5, 4, 3, 0,
65 31, 30, 29, 28, 27, 26, 25, 24,
66 23, 22, 21, 20, 19, 18, 17, 16,
67 16, 17, 18, 19, 20, 21, 22, 23,
68 24, 25, 26, 27, 28, 29, 30, 31,
69};
70
71static void cpm2_mask_irq(unsigned int irq_nr)
72{
73 int bit, word;
74 volatile uint *simr;
75
76 irq_nr -= CPM_IRQ_OFFSET;
77
78 bit = irq_to_siubit[irq_nr];
79 word = irq_to_siureg[irq_nr];
80
81 simr = &(cpm2_immr->im_intctl.ic_simrh);
82 ppc_cached_irq_mask[word] &= ~(1 << bit);
83 simr[word] = ppc_cached_irq_mask[word];
84}
85
86static void cpm2_unmask_irq(unsigned int irq_nr)
87{
88 int bit, word;
89 volatile uint *simr;
90
91 irq_nr -= CPM_IRQ_OFFSET;
92
93 bit = irq_to_siubit[irq_nr];
94 word = irq_to_siureg[irq_nr];
95
96 simr = &(cpm2_immr->im_intctl.ic_simrh);
97 ppc_cached_irq_mask[word] |= 1 << bit;
98 simr[word] = ppc_cached_irq_mask[word];
99}
100
101static void cpm2_mask_and_ack(unsigned int irq_nr)
102{
103 int bit, word;
104 volatile uint *simr, *sipnr;
105
106 irq_nr -= CPM_IRQ_OFFSET;
107
108 bit = irq_to_siubit[irq_nr];
109 word = irq_to_siureg[irq_nr];
110
111 simr = &(cpm2_immr->im_intctl.ic_simrh);
112 sipnr = &(cpm2_immr->im_intctl.ic_sipnrh);
113 ppc_cached_irq_mask[word] &= ~(1 << bit);
114 simr[word] = ppc_cached_irq_mask[word];
115 sipnr[word] = 1 << bit;
116}
117
118static void cpm2_end_irq(unsigned int irq_nr)
119{
120 int bit, word;
121 volatile uint *simr;
122
123 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
124 && irq_desc[irq_nr].action) {
125
126 irq_nr -= CPM_IRQ_OFFSET;
127 bit = irq_to_siubit[irq_nr];
128 word = irq_to_siureg[irq_nr];
129
130 simr = &(cpm2_immr->im_intctl.ic_simrh);
131 ppc_cached_irq_mask[word] |= 1 << bit;
132 simr[word] = ppc_cached_irq_mask[word];
133 /*
134 * Work around large numbers of spurious IRQs on PowerPC 82xx
135 * systems.
136 */
137 mb();
138 }
139}
140
141static struct irq_chip cpm2_pic = {
142 .typename = " CPM2 SIU ",
143 .enable = cpm2_unmask_irq,
144 .disable = cpm2_mask_irq,
145 .unmask = cpm2_unmask_irq,
146 .mask_ack = cpm2_mask_and_ack,
147 .end = cpm2_end_irq,
148};
149
150int cpm2_get_irq(struct pt_regs *regs)
151{
152 int irq;
153 unsigned long bits;
154
155 /* For CPM2, read the SIVEC register and shift the bits down
156 * to get the irq number.*/
157 bits = cpm2_immr->im_intctl.ic_sivec;
158 irq = bits >> 26;
159
160 if (irq == 0)
161 return(-1);
162 return irq+CPM_IRQ_OFFSET;
163}
164
165static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node)
166{
167 return cpm2_pic_node == NULL || cpm2_pic_node == node;
168}
169
170static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
171 irq_hw_number_t hw)
172{
173 pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw);
174
175 get_irq_desc(virq)->status |= IRQ_LEVEL;
176 set_irq_chip_and_handler(virq, &cpm2_pic, handle_level_irq);
177 return 0;
178}
179
180static void cpm2_host_unmap(struct irq_host *h, unsigned int virq)
181{
182 /* Make sure irq is masked in hardware */
183 cpm2_mask_irq(virq);
184
185 /* remove chip and handler */
186 set_irq_chip_and_handler(virq, NULL, NULL);
187}
188
189static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct,
190 u32 *intspec, unsigned int intsize,
191 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
192{
193 static const unsigned char map_cpm2_senses[4] = {
194 IRQ_TYPE_LEVEL_LOW,
195 IRQ_TYPE_LEVEL_HIGH,
196 IRQ_TYPE_EDGE_FALLING,
197 IRQ_TYPE_EDGE_RISING,
198 };
199
200 *out_hwirq = intspec[0];
201 if (intsize > 1 && intspec[1] < 4)
202 *out_flags = map_cpm2_senses[intspec[1]];
203 else
204 *out_flags = IRQ_TYPE_NONE;
205
206 return 0;
207}
208
209static struct irq_host_ops cpm2_pic_host_ops = {
210 .match = cpm2_pic_host_match,
211 .map = cpm2_pic_host_map,
212 .unmap = cpm2_host_unmap,
213 .xlate = cpm2_pic_host_xlate,
214};
215
216void cpm2_pic_init(struct device_node *node)
217{
218 int i;
219
220 /* Clear the CPM IRQ controller, in case it has any bits set
221 * from the bootloader
222 */
223
224 /* Mask out everything */
225
226 cpm2_immr->im_intctl.ic_simrh = 0x00000000;
227 cpm2_immr->im_intctl.ic_simrl = 0x00000000;
228
229 wmb();
230
231 /* Ack everything */
232 cpm2_immr->im_intctl.ic_sipnrh = 0xffffffff;
233 cpm2_immr->im_intctl.ic_sipnrl = 0xffffffff;
234 wmb();
235
236 /* Dummy read of the vector */
237 i = cpm2_immr->im_intctl.ic_sivec;
238 rmb();
239
240 /* Initialize the default interrupt mapping priorities,
241 * in case the boot rom changed something on us.
242 */
243 cpm2_immr->im_intctl.ic_sicr = 0;
244 cpm2_immr->im_intctl.ic_scprrh = 0x05309770;
245 cpm2_immr->im_intctl.ic_scprrl = 0x05309770;
246
247 /* create a legacy host */
248 if (node)
249 cpm2_pic_node = of_node_get(node);
250
251 cpm2_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm2_pic_host_ops, 64);
252 if (cpm2_pic_host == NULL) {
253 printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
254 return;
255 }
256}
diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/cpm2_pic.h
new file mode 100644
index 000000000000..436cca77db64
--- /dev/null
+++ b/arch/powerpc/sysdev/cpm2_pic.h
@@ -0,0 +1,8 @@
1#ifndef _PPC_KERNEL_CPM2_H
2#define _PPC_KERNEL_CPM2_H
3
4extern int cpm2_get_irq(struct pt_regs *regs);
5
6extern void cpm2_pic_init(struct device_node*);
7
8#endif /* _PPC_KERNEL_CPM2_H */
diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
index f6a7ff04ffe5..876974e5412f 100644
--- a/include/asm-ppc/cpm2.h
+++ b/include/asm-ppc/cpm2.h
@@ -42,6 +42,8 @@
42#define CPM_CR_IDMA4_SBLOCK (0x17) 42#define CPM_CR_IDMA4_SBLOCK (0x17)
43#define CPM_CR_MCC1_SBLOCK (0x1c) 43#define CPM_CR_MCC1_SBLOCK (0x1c)
44 44
45#define CPM_CR_FCC_SBLOCK(x) (x + 0x10)
46
45#define CPM_CR_SCC1_PAGE (0x00) 47#define CPM_CR_SCC1_PAGE (0x00)
46#define CPM_CR_SCC2_PAGE (0x01) 48#define CPM_CR_SCC2_PAGE (0x01)
47#define CPM_CR_SCC3_PAGE (0x02) 49#define CPM_CR_SCC3_PAGE (0x02)
@@ -62,6 +64,8 @@
62#define CPM_CR_MCC1_PAGE (0x07) 64#define CPM_CR_MCC1_PAGE (0x07)
63#define CPM_CR_MCC2_PAGE (0x08) 65#define CPM_CR_MCC2_PAGE (0x08)
64 66
67#define CPM_CR_FCC_PAGE(x) (x + 0x04)
68
65/* Some opcodes (there are more...later) 69/* Some opcodes (there are more...later)
66*/ 70*/
67#define CPM_CR_INIT_TRX ((ushort)0x0000) 71#define CPM_CR_INIT_TRX ((ushort)0x0000)
@@ -1186,7 +1190,7 @@ typedef struct im_idma {
1186#define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128)) 1190#define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
1187#define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0) 1191#define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
1188#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1) 1192#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
1189#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(2) 1193#define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2)
1190 1194
1191#endif /* __CPM2__ */ 1195#endif /* __CPM2__ */
1192#endif /* __KERNEL__ */ 1196#endif /* __KERNEL__ */