aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2006-09-27 17:18:28 -0400
committerPaul Mackerras <paulus@samba.org>2006-09-27 17:18:28 -0400
commit4e6d816e51728d5006c53e78e079ac62b902f8aa (patch)
treed388c87dabc063c08c52d17610738d2f49b3855c /arch/powerpc/sysdev
parentd86d9b8cab45adf64e2ea8fe975bec3282b5de81 (diff)
parent611a15afcdaacec6efba984c7eb089b853564bdf (diff)
Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/vitb/linux-2.6-PQ
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/Makefile5
-rw-r--r--arch/powerpc/sysdev/cpm2_common.c309
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.c256
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.h10
-rw-r--r--arch/powerpc/sysdev/fsl_soc.c281
-rw-r--r--arch/powerpc/sysdev/fsl_soc.h2
6 files changed, 858 insertions, 5 deletions
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..ec265995d5d8
--- /dev/null
+++ b/arch/powerpc/sysdev/cpm2_common.c
@@ -0,0 +1,309 @@
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;
54intctl_cpm2_t *cpm2_intctl;
55
56#define CPM_MAP_SIZE (0x40000) /* 256k - the PQ3 reserve this amount
57 of space for CPM as it is larger
58 than on PQ2 */
59
60void
61cpm2_reset(void)
62{
63 cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
64 cpm2_intctl = cpm2_map(im_intctl);
65
66 /* Reclaim the DP memory for our use.
67 */
68 cpm2_dpinit();
69
70 /* Tell everyone where the comm processor resides.
71 */
72 cpmp = &cpm2_immr->im_cpm;
73}
74
75/* Set a baud rate generator. This needs lots of work. There are
76 * eight BRGs, which can be connected to the CPM channels or output
77 * as clocks. The BRGs are in two different block of internal
78 * memory mapped space.
79 * The baud rate clock is the system clock divided by something.
80 * It was set up long ago during the initial boot phase and is
81 * is given to us.
82 * Baud rate clocks are zero-based in the driver code (as that maps
83 * to port numbers). Documentation uses 1-based numbering.
84 */
85#define BRG_INT_CLK (get_brgfreq())
86#define BRG_UART_CLK (BRG_INT_CLK/16)
87
88/* This function is used by UARTS, or anything else that uses a 16x
89 * oversampled clock.
90 */
91void
92cpm_setbrg(uint brg, uint rate)
93{
94 volatile uint *bp;
95
96 /* This is good enough to get SMCs running.....
97 */
98 if (brg < 4) {
99 bp = cpm2_map_size(im_brgc1, 16);
100 } else {
101 bp = cpm2_map_size(im_brgc5, 16);
102 brg -= 4;
103 }
104 bp += brg;
105 *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
106
107 cpm2_unmap(bp);
108}
109
110/* This function is used to set high speed synchronous baud rate
111 * clocks.
112 */
113void
114cpm2_fastbrg(uint brg, uint rate, int div16)
115{
116 volatile uint *bp;
117
118 if (brg < 4) {
119 bp = cpm2_map_size(im_brgc1, 16);
120 }
121 else {
122 bp = cpm2_map_size(im_brgc5, 16);
123 brg -= 4;
124 }
125 bp += brg;
126 *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
127 if (div16)
128 *bp |= CPM_BRG_DIV16;
129
130 cpm2_unmap(bp);
131}
132
133int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
134{
135 int ret = 0;
136 int shift;
137 int i, bits = 0;
138 cpmux_t *im_cpmux;
139 u32 *reg;
140 u32 mask = 7;
141 u8 clk_map [24][3] = {
142 {CPM_CLK_FCC1, CPM_BRG5, 0},
143 {CPM_CLK_FCC1, CPM_BRG6, 1},
144 {CPM_CLK_FCC1, CPM_BRG7, 2},
145 {CPM_CLK_FCC1, CPM_BRG8, 3},
146 {CPM_CLK_FCC1, CPM_CLK9, 4},
147 {CPM_CLK_FCC1, CPM_CLK10, 5},
148 {CPM_CLK_FCC1, CPM_CLK11, 6},
149 {CPM_CLK_FCC1, CPM_CLK12, 7},
150 {CPM_CLK_FCC2, CPM_BRG5, 0},
151 {CPM_CLK_FCC2, CPM_BRG6, 1},
152 {CPM_CLK_FCC2, CPM_BRG7, 2},
153 {CPM_CLK_FCC2, CPM_BRG8, 3},
154 {CPM_CLK_FCC2, CPM_CLK13, 4},
155 {CPM_CLK_FCC2, CPM_CLK14, 5},
156 {CPM_CLK_FCC2, CPM_CLK15, 6},
157 {CPM_CLK_FCC2, CPM_CLK16, 7},
158 {CPM_CLK_FCC3, CPM_BRG5, 0},
159 {CPM_CLK_FCC3, CPM_BRG6, 1},
160 {CPM_CLK_FCC3, CPM_BRG7, 2},
161 {CPM_CLK_FCC3, CPM_BRG8, 3},
162 {CPM_CLK_FCC3, CPM_CLK13, 4},
163 {CPM_CLK_FCC3, CPM_CLK14, 5},
164 {CPM_CLK_FCC3, CPM_CLK15, 6},
165 {CPM_CLK_FCC3, CPM_CLK16, 7}
166 };
167
168 im_cpmux = cpm2_map(im_cpmux);
169
170 switch (target) {
171 case CPM_CLK_SCC1:
172 reg = &im_cpmux->cmx_scr;
173 shift = 24;
174 case CPM_CLK_SCC2:
175 reg = &im_cpmux->cmx_scr;
176 shift = 16;
177 break;
178 case CPM_CLK_SCC3:
179 reg = &im_cpmux->cmx_scr;
180 shift = 8;
181 break;
182 case CPM_CLK_SCC4:
183 reg = &im_cpmux->cmx_scr;
184 shift = 0;
185 break;
186 case CPM_CLK_FCC1:
187 reg = &im_cpmux->cmx_fcr;
188 shift = 24;
189 break;
190 case CPM_CLK_FCC2:
191 reg = &im_cpmux->cmx_fcr;
192 shift = 16;
193 break;
194 case CPM_CLK_FCC3:
195 reg = &im_cpmux->cmx_fcr;
196 shift = 8;
197 break;
198 default:
199 printk(KERN_ERR "cpm2_clock_setup: invalid clock target\n");
200 return -EINVAL;
201 }
202
203 if (mode == CPM_CLK_RX)
204 shift +=3;
205
206 for (i=0; i<24; i++) {
207 if (clk_map[i][0] == target && clk_map[i][1] == clock) {
208 bits = clk_map[i][2];
209 break;
210 }
211 }
212 if (i == sizeof(clk_map)/3)
213 ret = -EINVAL;
214
215 bits <<= shift;
216 mask <<= shift;
217 out_be32(reg, (in_be32(reg) & ~mask) | bits);
218
219 cpm2_unmap(im_cpmux);
220 return ret;
221}
222
223/*
224 * dpalloc / dpfree bits.
225 */
226static spinlock_t cpm_dpmem_lock;
227/* 16 blocks should be enough to satisfy all requests
228 * until the memory subsystem goes up... */
229static rh_block_t cpm_boot_dpmem_rh_block[16];
230static rh_info_t cpm_dpmem_info;
231static u8* im_dprambase;
232
233static void cpm2_dpinit(void)
234{
235 spin_lock_init(&cpm_dpmem_lock);
236
237 im_dprambase = ioremap(CPM_MAP_ADDR, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE);
238
239 /* initialize the info header */
240 rh_init(&cpm_dpmem_info, 1,
241 sizeof(cpm_boot_dpmem_rh_block) /
242 sizeof(cpm_boot_dpmem_rh_block[0]),
243 cpm_boot_dpmem_rh_block);
244
245 /* Attach the usable dpmem area */
246 /* XXX: This is actually crap. CPM_DATAONLY_BASE and
247 * CPM_DATAONLY_SIZE is only a subset of the available dpram. It
248 * varies with the processor and the microcode patches activated.
249 * But the following should be at least safe.
250 */
251 rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE,
252 CPM_DATAONLY_SIZE);
253}
254
255/* This function returns an index into the DPRAM area.
256 */
257uint cpm_dpalloc(uint size, uint align)
258{
259 void *start;
260 unsigned long flags;
261
262 spin_lock_irqsave(&cpm_dpmem_lock, flags);
263 cpm_dpmem_info.alignment = align;
264 start = rh_alloc(&cpm_dpmem_info, size, "commproc");
265 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
266
267 return (uint)start;
268}
269EXPORT_SYMBOL(cpm_dpalloc);
270
271int cpm_dpfree(uint offset)
272{
273 int ret;
274 unsigned long flags;
275
276 spin_lock_irqsave(&cpm_dpmem_lock, flags);
277 ret = rh_free(&cpm_dpmem_info, (void *)offset);
278 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
279
280 return ret;
281}
282EXPORT_SYMBOL(cpm_dpfree);
283
284/* not sure if this is ever needed */
285uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
286{
287 void *start;
288 unsigned long flags;
289
290 spin_lock_irqsave(&cpm_dpmem_lock, flags);
291 cpm_dpmem_info.alignment = align;
292 start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
293 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
294
295 return (uint)start;
296}
297EXPORT_SYMBOL(cpm_dpalloc_fixed);
298
299void cpm_dpdump(void)
300{
301 rh_dump(&cpm_dpmem_info);
302}
303EXPORT_SYMBOL(cpm_dpdump);
304
305void *cpm_dpram_addr(uint offset)
306{
307 return (void *)(im_dprambase + offset);
308}
309EXPORT_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..51752990f7b9
--- /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_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_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_intctl->ic_simrh);
112 sipnr = &(cpm2_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_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_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_intctl->ic_simrh = 0x00000000;
227 cpm2_intctl->ic_simrl = 0x00000000;
228
229 wmb();
230
231 /* Ack everything */
232 cpm2_intctl->ic_sipnrh = 0xffffffff;
233 cpm2_intctl->ic_sipnrl = 0xffffffff;
234 wmb();
235
236 /* Dummy read of the vector */
237 i = cpm2_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_intctl->ic_sicr = 0;
244 cpm2_intctl->ic_scprrh = 0x05309770;
245 cpm2_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..d63e45d4df58
--- /dev/null
+++ b/arch/powerpc/sysdev/cpm2_pic.h
@@ -0,0 +1,10 @@
1#ifndef _PPC_KERNEL_CPM2_H
2#define _PPC_KERNEL_CPM2_H
3
4extern intctl_cpm2_t *cpm2_intctl;
5
6extern int cpm2_get_irq(struct pt_regs *regs);
7
8extern void cpm2_pic_init(struct device_node*);
9
10#endif /* _PPC_KERNEL_CPM2_H */
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 92ba378b7990..022ed275ea68 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -3,6 +3,9 @@
3 * 3 *
4 * Maintained by Kumar Gala (see MAINTAINERS for contact information) 4 * Maintained by Kumar Gala (see MAINTAINERS for contact information)
5 * 5 *
6 * 2006 (c) MontaVista Software, Inc.
7 * Vitaly Bordug <vbordug@ru.mvista.com>
8 *
6 * This program is free software; you can redistribute it and/or modify it 9 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the 10 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your 11 * Free Software Foundation; either version 2 of the License, or (at your
@@ -20,15 +23,20 @@
20#include <linux/device.h> 23#include <linux/device.h>
21#include <linux/platform_device.h> 24#include <linux/platform_device.h>
22#include <linux/fsl_devices.h> 25#include <linux/fsl_devices.h>
26#include <linux/fs_enet_pd.h>
27#include <linux/fs_uart_pd.h>
23 28
24#include <asm/system.h> 29#include <asm/system.h>
25#include <asm/atomic.h> 30#include <asm/atomic.h>
26#include <asm/io.h> 31#include <asm/io.h>
27#include <asm/irq.h> 32#include <asm/irq.h>
33#include <asm/time.h>
28#include <asm/prom.h> 34#include <asm/prom.h>
29#include <sysdev/fsl_soc.h> 35#include <sysdev/fsl_soc.h>
30#include <mm/mmu_decl.h> 36#include <mm/mmu_decl.h>
37#include <asm/cpm2.h>
31 38
39extern void init_fcc_ioports(struct fs_platform_info*);
32static phys_addr_t immrbase = -1; 40static phys_addr_t immrbase = -1;
33 41
34phys_addr_t get_immrbase(void) 42phys_addr_t get_immrbase(void)
@@ -42,7 +50,9 @@ phys_addr_t get_immrbase(void)
42 if (soc) { 50 if (soc) {
43 unsigned int size; 51 unsigned int size;
44 const void *prop = get_property(soc, "reg", &size); 52 const void *prop = get_property(soc, "reg", &size);
45 immrbase = of_translate_address(soc, prop); 53
54 if (prop)
55 immrbase = of_translate_address(soc, prop);
46 of_node_put(soc); 56 of_node_put(soc);
47 }; 57 };
48 58
@@ -51,6 +61,59 @@ phys_addr_t get_immrbase(void)
51 61
52EXPORT_SYMBOL(get_immrbase); 62EXPORT_SYMBOL(get_immrbase);
53 63
64#ifdef CONFIG_CPM2
65
66static u32 brgfreq = -1;
67
68u32 get_brgfreq(void)
69{
70 struct device_node *node;
71
72 if (brgfreq != -1)
73 return brgfreq;
74
75 node = of_find_node_by_type(NULL, "cpm");
76 if (node) {
77 unsigned int size;
78 const unsigned int *prop = get_property(node, "brg-frequency",
79 &size);
80
81 if (prop)
82 brgfreq = *prop;
83 of_node_put(node);
84 };
85
86 return brgfreq;
87}
88
89EXPORT_SYMBOL(get_brgfreq);
90
91static u32 fs_baudrate = -1;
92
93u32 get_baudrate(void)
94{
95 struct device_node *node;
96
97 if (fs_baudrate != -1)
98 return fs_baudrate;
99
100 node = of_find_node_by_type(NULL, "serial");
101 if (node) {
102 unsigned int size;
103 const unsigned int *prop = get_property(node, "current-speed",
104 &size);
105
106 if (prop)
107 fs_baudrate = *prop;
108 of_node_put(node);
109 };
110
111 return fs_baudrate;
112}
113
114EXPORT_SYMBOL(get_baudrate);
115#endif /* CONFIG_CPM2 */
116
54static int __init gfar_mdio_of_init(void) 117static int __init gfar_mdio_of_init(void)
55{ 118{
56 struct device_node *np; 119 struct device_node *np;
@@ -85,8 +148,11 @@ static int __init gfar_mdio_of_init(void)
85 mdio_data.irq[k] = -1; 148 mdio_data.irq[k] = -1;
86 149
87 while ((child = of_get_next_child(np, child)) != NULL) { 150 while ((child = of_get_next_child(np, child)) != NULL) {
88 const u32 *id = get_property(child, "reg", NULL); 151 int irq = irq_of_parse_and_map(child, 0);
89 mdio_data.irq[*id] = irq_of_parse_and_map(child, 0); 152 if (irq != NO_IRQ) {
153 const u32 *id = get_property(child, "reg", NULL);
154 mdio_data.irq[*id] = irq;
155 }
90 } 156 }
91 157
92 ret = 158 ret =
@@ -128,7 +194,7 @@ static int __init gfar_of_init(void)
128 const char *model; 194 const char *model;
129 const void *mac_addr; 195 const void *mac_addr;
130 const phandle *ph; 196 const phandle *ph;
131 int n_res = 1; 197 int n_res = 2;
132 198
133 memset(r, 0, sizeof(r)); 199 memset(r, 0, sizeof(r));
134 memset(&gfar_data, 0, sizeof(gfar_data)); 200 memset(&gfar_data, 0, sizeof(gfar_data));
@@ -159,7 +225,7 @@ static int __init gfar_of_init(void)
159 225
160 gfar_dev = 226 gfar_dev =
161 platform_device_register_simple("fsl-gianfar", i, &r[0], 227 platform_device_register_simple("fsl-gianfar", i, &r[0],
162 n_res + 1); 228 n_res);
163 229
164 if (IS_ERR(gfar_dev)) { 230 if (IS_ERR(gfar_dev)) {
165 ret = PTR_ERR(gfar_dev); 231 ret = PTR_ERR(gfar_dev);
@@ -478,3 +544,208 @@ err:
478} 544}
479 545
480arch_initcall(fsl_usb_of_init); 546arch_initcall(fsl_usb_of_init);
547
548#ifdef CONFIG_CPM2
549
550static const char fcc_regs[] = "fcc_regs";
551static const char fcc_regs_c[] = "fcc_regs_c";
552static const char fcc_pram[] = "fcc_pram";
553static char bus_id[9][BUS_ID_SIZE];
554
555static int __init fs_enet_of_init(void)
556{
557 struct device_node *np;
558 unsigned int i;
559 struct platform_device *fs_enet_dev;
560 struct resource res;
561 int ret;
562
563 for (np = NULL, i = 0;
564 (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL;
565 i++) {
566 struct resource r[4];
567 struct device_node *phy, *mdio;
568 struct fs_platform_info fs_enet_data;
569 const unsigned int *id, *phy_addr;
570 const void *mac_addr;
571 const phandle *ph;
572 const char *model;
573
574 memset(r, 0, sizeof(r));
575 memset(&fs_enet_data, 0, sizeof(fs_enet_data));
576
577 ret = of_address_to_resource(np, 0, &r[0]);
578 if (ret)
579 goto err;
580 r[0].name = fcc_regs;
581
582 ret = of_address_to_resource(np, 1, &r[1]);
583 if (ret)
584 goto err;
585 r[1].name = fcc_pram;
586
587 ret = of_address_to_resource(np, 2, &r[2]);
588 if (ret)
589 goto err;
590 r[2].name = fcc_regs_c;
591
592 r[3].start = r[3].end = irq_of_parse_and_map(np, 0);
593 r[3].flags = IORESOURCE_IRQ;
594
595 fs_enet_dev =
596 platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4);
597
598 if (IS_ERR(fs_enet_dev)) {
599 ret = PTR_ERR(fs_enet_dev);
600 goto err;
601 }
602
603 model = get_property(np, "model", NULL);
604 if (model == NULL) {
605 ret = -ENODEV;
606 goto unreg;
607 }
608
609 mac_addr = get_property(np, "mac-address", NULL);
610 memcpy(fs_enet_data.macaddr, mac_addr, 6);
611
612 ph = get_property(np, "phy-handle", NULL);
613 phy = of_find_node_by_phandle(*ph);
614
615 if (phy == NULL) {
616 ret = -ENODEV;
617 goto unreg;
618 }
619
620 phy_addr = get_property(phy, "reg", NULL);
621 fs_enet_data.phy_addr = *phy_addr;
622
623 id = get_property(np, "device-id", NULL);
624 fs_enet_data.fs_no = *id;
625 strcpy(fs_enet_data.fs_type, model);
626
627 mdio = of_get_parent(phy);
628 ret = of_address_to_resource(mdio, 0, &res);
629 if (ret) {
630 of_node_put(phy);
631 of_node_put(mdio);
632 goto unreg;
633 }
634
635 fs_enet_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
636 fs_enet_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
637
638 if (strstr(model, "FCC")) {
639 int fcc_index = *id - 1;
640
641 fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0);
642 fs_enet_data.rx_ring = 32;
643 fs_enet_data.tx_ring = 32;
644 fs_enet_data.rx_copybreak = 240;
645 fs_enet_data.use_napi = 0;
646 fs_enet_data.napi_weight = 17;
647 fs_enet_data.mem_offset = FCC_MEM_OFFSET(fcc_index);
648 fs_enet_data.cp_page = CPM_CR_FCC_PAGE(fcc_index);
649 fs_enet_data.cp_block = CPM_CR_FCC_SBLOCK(fcc_index);
650
651 snprintf((char*)&bus_id[(*id)], BUS_ID_SIZE, "%x:%02x",
652 (u32)res.start, fs_enet_data.phy_addr);
653 fs_enet_data.bus_id = (char*)&bus_id[(*id)];
654 fs_enet_data.init_ioports = init_fcc_ioports;
655 }
656
657 of_node_put(phy);
658 of_node_put(mdio);
659
660 ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
661 sizeof(struct
662 fs_platform_info));
663 if (ret)
664 goto unreg;
665 }
666 return 0;
667
668unreg:
669 platform_device_unregister(fs_enet_dev);
670err:
671 return ret;
672}
673
674arch_initcall(fs_enet_of_init);
675
676static const char scc_regs[] = "regs";
677static const char scc_pram[] = "pram";
678
679static int __init cpm_uart_of_init(void)
680{
681 struct device_node *np;
682 unsigned int i;
683 struct platform_device *cpm_uart_dev;
684 int ret;
685
686 for (np = NULL, i = 0;
687 (np = of_find_compatible_node(np, "serial", "cpm_uart")) != NULL;
688 i++) {
689 struct resource r[3];
690 struct fs_uart_platform_info cpm_uart_data;
691 const int *id;
692 const char *model;
693
694 memset(r, 0, sizeof(r));
695 memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
696
697 ret = of_address_to_resource(np, 0, &r[0]);
698 if (ret)
699 goto err;
700
701 r[0].name = scc_regs;
702
703 ret = of_address_to_resource(np, 1, &r[1]);
704 if (ret)
705 goto err;
706 r[1].name = scc_pram;
707
708 r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
709 r[2].flags = IORESOURCE_IRQ;
710
711 cpm_uart_dev =
712 platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3);
713
714 if (IS_ERR(cpm_uart_dev)) {
715 ret = PTR_ERR(cpm_uart_dev);
716 goto err;
717 }
718
719 id = get_property(np, "device-id", NULL);
720 cpm_uart_data.fs_no = *id;
721
722 model = (char*)get_property(np, "model", NULL);
723 strcpy(cpm_uart_data.fs_type, model);
724
725 cpm_uart_data.uart_clk = ppc_proc_freq;
726
727 cpm_uart_data.tx_num_fifo = 4;
728 cpm_uart_data.tx_buf_size = 32;
729 cpm_uart_data.rx_num_fifo = 4;
730 cpm_uart_data.rx_buf_size = 32;
731 cpm_uart_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
732 cpm_uart_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
733
734 ret =
735 platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
736 sizeof(struct
737 fs_uart_platform_info));
738 if (ret)
739 goto unreg;
740 }
741
742 return 0;
743
744unreg:
745 platform_device_unregister(cpm_uart_dev);
746err:
747 return ret;
748}
749
750arch_initcall(cpm_uart_of_init);
751#endif /* CONFIG_CPM2 */
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 5a3dd480d2fd..04e145b5fc32 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -5,6 +5,8 @@
5#include <asm/mmu.h> 5#include <asm/mmu.h>
6 6
7extern phys_addr_t get_immrbase(void); 7extern phys_addr_t get_immrbase(void);
8extern u32 get_brgfreq(void);
9extern u32 get_baudrate(void);
8 10
9#endif 11#endif
10#endif 12#endif