aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc/8xx_io/commproc.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/8xx_io/commproc.c')
-rw-r--r--arch/ppc/8xx_io/commproc.c432
1 files changed, 0 insertions, 432 deletions
diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
deleted file mode 100644
index 752443df5ecf..000000000000
--- a/arch/ppc/8xx_io/commproc.c
+++ /dev/null
@@ -1,432 +0,0 @@
1/*
2 * General Purpose functions for the global management of the
3 * Communication Processor Module.
4 * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
5 *
6 * In addition to the individual control of the communication
7 * channels, there are a few functions that globally affect the
8 * communication processor.
9 *
10 * Buffer descriptors must be allocated from the dual ported memory
11 * space. The allocator for that is here. When the communication
12 * process is reset, we reclaim the memory available. There is
13 * currently no deallocator for this memory.
14 * The amount of space available is platform dependent. On the
15 * MBX, the EPPC software loads additional microcode into the
16 * communication processor, and uses some of the DP ram for this
17 * purpose. Current, the first 512 bytes and the last 256 bytes of
18 * memory are used. Right now I am conservative and only use the
19 * memory that can never be used for microcode. If there are
20 * applications that require more DP ram, we can expand the boundaries
21 * but then we have to be careful of any downloaded microcode.
22 */
23#include <linux/errno.h>
24#include <linux/sched.h>
25#include <linux/kernel.h>
26#include <linux/dma-mapping.h>
27#include <linux/param.h>
28#include <linux/string.h>
29#include <linux/mm.h>
30#include <linux/interrupt.h>
31#include <linux/irq.h>
32#include <linux/module.h>
33#include <asm/mpc8xx.h>
34#include <asm/page.h>
35#include <asm/pgtable.h>
36#include <asm/8xx_immap.h>
37#include <asm/cpm1.h>
38#include <asm/io.h>
39#include <asm/tlbflush.h>
40#include <asm/rheap.h>
41
42#define immr_map(member) \
43({ \
44 u32 offset = offsetof(immap_t, member); \
45 void *addr = ioremap (IMAP_ADDR + offset, \
46 FIELD_SIZEOF(immap_t, member)); \
47 addr; \
48})
49
50#define immr_map_size(member, size) \
51({ \
52 u32 offset = offsetof(immap_t, member); \
53 void *addr = ioremap (IMAP_ADDR + offset, size); \
54 addr; \
55})
56
57static void m8xx_cpm_dpinit(void);
58cpm8xx_t *cpmp; /* Pointer to comm processor space */
59
60/* CPM interrupt vector functions.
61*/
62struct cpm_action {
63 void (*handler)(void *);
64 void *dev_id;
65};
66static struct cpm_action cpm_vecs[CPMVEC_NR];
67static irqreturn_t cpm_interrupt(int irq, void * dev);
68static irqreturn_t cpm_error_interrupt(int irq, void *dev);
69/* Define a table of names to identify CPM interrupt handlers in
70 * /proc/interrupts.
71 */
72const char *cpm_int_name[] =
73 { "error", "PC4", "PC5", "SMC2",
74 "SMC1", "SPI", "PC6", "Timer 4",
75 "", "PC7", "PC8", "PC9",
76 "Timer 3", "", "PC10", "PC11",
77 "I2C", "RISC Timer", "Timer 2", "",
78 "IDMA2", "IDMA1", "SDMA error", "PC12",
79 "PC13", "Timer 1", "PC14", "SCC4",
80 "SCC3", "SCC2", "SCC1", "PC15"
81 };
82
83static void
84cpm_mask_irq(unsigned int irq)
85{
86 int cpm_vec = irq - CPM_IRQ_OFFSET;
87
88 clrbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, (1 << cpm_vec));
89}
90
91static void
92cpm_unmask_irq(unsigned int irq)
93{
94 int cpm_vec = irq - CPM_IRQ_OFFSET;
95
96 setbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, (1 << cpm_vec));
97}
98
99static void
100cpm_ack(unsigned int irq)
101{
102 /* We do not need to do anything here. */
103}
104
105static void
106cpm_eoi(unsigned int irq)
107{
108 int cpm_vec = irq - CPM_IRQ_OFFSET;
109
110 out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr, (1 << cpm_vec));
111}
112
113struct hw_interrupt_type cpm_pic = {
114 .typename = " CPM ",
115 .enable = cpm_unmask_irq,
116 .disable = cpm_mask_irq,
117 .ack = cpm_ack,
118 .end = cpm_eoi,
119};
120
121void
122m8xx_cpm_reset(void)
123{
124 volatile immap_t *imp;
125 volatile cpm8xx_t *commproc;
126
127 imp = (immap_t *)IMAP_ADDR;
128 commproc = (cpm8xx_t *)&imp->im_cpm;
129
130#ifdef CONFIG_UCODE_PATCH
131 /* Perform a reset.
132 */
133 commproc->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG);
134
135 /* Wait for it.
136 */
137 while (commproc->cp_cpcr & CPM_CR_FLG);
138
139 cpm_load_patch(imp);
140#endif
141
142 /* Set SDMA Bus Request priority 5.
143 * On 860T, this also enables FEC priority 6. I am not sure
144 * this is what we really want for some applications, but the
145 * manual recommends it.
146 * Bit 25, FAM can also be set to use FEC aggressive mode (860T).
147 */
148 out_be32(&imp->im_siu_conf.sc_sdcr, 1),
149
150 /* Reclaim the DP memory for our use. */
151 m8xx_cpm_dpinit();
152
153 /* Tell everyone where the comm processor resides.
154 */
155 cpmp = (cpm8xx_t *)commproc;
156}
157
158/* This is called during init_IRQ. We used to do it above, but this
159 * was too early since init_IRQ was not yet called.
160 */
161static struct irqaction cpm_error_irqaction = {
162 .handler = cpm_error_interrupt,
163 .mask = CPU_MASK_NONE,
164};
165static struct irqaction cpm_interrupt_irqaction = {
166 .handler = cpm_interrupt,
167 .mask = CPU_MASK_NONE,
168 .name = "CPM cascade",
169};
170
171void
172cpm_interrupt_init(void)
173{
174 int i;
175
176 /* Initialize the CPM interrupt controller.
177 */
178 out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr,
179 (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
180 ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK);
181 out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, 0);
182
183 /* install the CPM interrupt controller routines for the CPM
184 * interrupt vectors
185 */
186 for ( i = CPM_IRQ_OFFSET ; i < CPM_IRQ_OFFSET + NR_CPM_INTS ; i++ )
187 irq_desc[i].chip = &cpm_pic;
188
189 /* Set our interrupt handler with the core CPU. */
190 if (setup_irq(CPM_INTERRUPT, &cpm_interrupt_irqaction))
191 panic("Could not allocate CPM IRQ!");
192
193 /* Install our own error handler. */
194 cpm_error_irqaction.name = cpm_int_name[CPMVEC_ERROR];
195 if (setup_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, &cpm_error_irqaction))
196 panic("Could not allocate CPM error IRQ!");
197
198 setbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr, CICR_IEN);
199}
200
201/*
202 * Get the CPM interrupt vector.
203 */
204int
205cpm_get_irq(void)
206{
207 int cpm_vec;
208
209 /* Get the vector by setting the ACK bit and then reading
210 * the register.
211 */
212 out_be16(&((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr, 1);
213 cpm_vec = in_be16(&((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr);
214 cpm_vec >>= 11;
215
216 return cpm_vec;
217}
218
219/* CPM interrupt controller cascade interrupt.
220*/
221static irqreturn_t
222cpm_interrupt(int irq, void * dev)
223{
224 /* This interrupt handler never actually gets called. It is
225 * installed only to unmask the CPM cascade interrupt in the SIU
226 * and to make the CPM cascade interrupt visible in /proc/interrupts.
227 */
228 return IRQ_HANDLED;
229}
230
231/* The CPM can generate the error interrupt when there is a race condition
232 * between generating and masking interrupts. All we have to do is ACK it
233 * and return. This is a no-op function so we don't need any special
234 * tests in the interrupt handler.
235 */
236static irqreturn_t
237cpm_error_interrupt(int irq, void *dev)
238{
239 return IRQ_HANDLED;
240}
241
242/* A helper function to translate the handler prototype required by
243 * request_irq() to the handler prototype required by cpm_install_handler().
244 */
245static irqreturn_t
246cpm_handler_helper(int irq, void *dev_id)
247{
248 int cpm_vec = irq - CPM_IRQ_OFFSET;
249
250 (*cpm_vecs[cpm_vec].handler)(dev_id);
251
252 return IRQ_HANDLED;
253}
254
255/* Install a CPM interrupt handler.
256 * This routine accepts a CPM interrupt vector in the range 0 to 31.
257 * This routine is retained for backward compatibility. Rather than using
258 * this routine to install a CPM interrupt handler, you can now use
259 * request_irq() with an IRQ in the range CPM_IRQ_OFFSET to
260 * CPM_IRQ_OFFSET + NR_CPM_INTS - 1 (16 to 47).
261 *
262 * Notice that the prototype of the interrupt handler function must be
263 * different depending on whether you install the handler with
264 * request_irq() or cpm_install_handler().
265 */
266void
267cpm_install_handler(int cpm_vec, void (*handler)(void *), void *dev_id)
268{
269 int err;
270
271 /* If null handler, assume we are trying to free the IRQ.
272 */
273 if (!handler) {
274 free_irq(CPM_IRQ_OFFSET + cpm_vec, dev_id);
275 return;
276 }
277
278 if (cpm_vecs[cpm_vec].handler != 0)
279 printk(KERN_INFO "CPM interrupt %x replacing %x\n",
280 (uint)handler, (uint)cpm_vecs[cpm_vec].handler);
281 cpm_vecs[cpm_vec].handler = handler;
282 cpm_vecs[cpm_vec].dev_id = dev_id;
283
284 if ((err = request_irq(CPM_IRQ_OFFSET + cpm_vec, cpm_handler_helper,
285 0, cpm_int_name[cpm_vec], dev_id)))
286 printk(KERN_ERR "request_irq() returned %d for CPM vector %d\n",
287 err, cpm_vec);
288}
289
290/* Free a CPM interrupt handler.
291 * This routine accepts a CPM interrupt vector in the range 0 to 31.
292 * This routine is retained for backward compatibility.
293 */
294void
295cpm_free_handler(int cpm_vec)
296{
297 request_irq(CPM_IRQ_OFFSET + cpm_vec, NULL, 0, 0,
298 cpm_vecs[cpm_vec].dev_id);
299
300 cpm_vecs[cpm_vec].handler = NULL;
301 cpm_vecs[cpm_vec].dev_id = NULL;
302}
303
304/* Set a baud rate generator. This needs lots of work. There are
305 * four BRGs, any of which can be wired to any channel.
306 * The internal baud rate clock is the system clock divided by 16.
307 * This assumes the baudrate is 16x oversampled by the uart.
308 */
309#define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq)
310#define BRG_UART_CLK (BRG_INT_CLK/16)
311#define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16)
312
313void
314cpm_setbrg(uint brg, uint rate)
315{
316 volatile uint *bp;
317
318 /* This is good enough to get SMCs running.....
319 */
320 bp = (uint *)&cpmp->cp_brgc1;
321 bp += brg;
322 /* The BRG has a 12-bit counter. For really slow baud rates (or
323 * really fast processors), we may have to further divide by 16.
324 */
325 if (((BRG_UART_CLK / rate) - 1) < 4096)
326 *bp = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN;
327 else
328 *bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
329 CPM_BRG_EN | CPM_BRG_DIV16;
330}
331
332/*
333 * dpalloc / dpfree bits.
334 */
335static spinlock_t cpm_dpmem_lock;
336/*
337 * 16 blocks should be enough to satisfy all requests
338 * until the memory subsystem goes up...
339 */
340static rh_block_t cpm_boot_dpmem_rh_block[16];
341static rh_info_t cpm_dpmem_info;
342
343#define CPM_DPMEM_ALIGNMENT 8
344static u8* dpram_vbase;
345static uint dpram_pbase;
346
347void m8xx_cpm_dpinit(void)
348{
349 spin_lock_init(&cpm_dpmem_lock);
350
351 dpram_vbase = immr_map_size(im_cpm.cp_dpmem, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE);
352 dpram_pbase = (uint)&((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem;
353
354 /* Initialize the info header */
355 rh_init(&cpm_dpmem_info, CPM_DPMEM_ALIGNMENT,
356 sizeof(cpm_boot_dpmem_rh_block) /
357 sizeof(cpm_boot_dpmem_rh_block[0]),
358 cpm_boot_dpmem_rh_block);
359
360 /*
361 * Attach the usable dpmem area.
362 * XXX: This is actually crap. CPM_DATAONLY_BASE and
363 * CPM_DATAONLY_SIZE are a subset of the available dparm. It varies
364 * with the processor and the microcode patches applied / activated.
365 * But the following should be at least safe.
366 */
367 rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
368}
369
370/*
371 * Allocate the requested size worth of DP memory.
372 * This function returns an offset into the DPRAM area.
373 * Use cpm_dpram_addr() to get the virtual address of the area.
374 */
375unsigned long cpm_dpalloc(uint size, uint align)
376{
377 unsigned long start;
378 unsigned long flags;
379
380 spin_lock_irqsave(&cpm_dpmem_lock, flags);
381 cpm_dpmem_info.alignment = align;
382 start = rh_alloc(&cpm_dpmem_info, size, "commproc");
383 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
384
385 return start;
386}
387EXPORT_SYMBOL(cpm_dpalloc);
388
389int cpm_dpfree(unsigned long offset)
390{
391 int ret;
392 unsigned long flags;
393
394 spin_lock_irqsave(&cpm_dpmem_lock, flags);
395 ret = rh_free(&cpm_dpmem_info, offset);
396 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
397
398 return ret;
399}
400EXPORT_SYMBOL(cpm_dpfree);
401
402unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align)
403{
404 unsigned long start;
405 unsigned long flags;
406
407 spin_lock_irqsave(&cpm_dpmem_lock, flags);
408 cpm_dpmem_info.alignment = align;
409 start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc");
410 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
411
412 return start;
413}
414EXPORT_SYMBOL(cpm_dpalloc_fixed);
415
416void cpm_dpdump(void)
417{
418 rh_dump(&cpm_dpmem_info);
419}
420EXPORT_SYMBOL(cpm_dpdump);
421
422void *cpm_dpram_addr(unsigned long offset)
423{
424 return (void *)(dpram_vbase + offset);
425}
426EXPORT_SYMBOL(cpm_dpram_addr);
427
428uint cpm_dpram_phys(u8* addr)
429{
430 return (dpram_pbase + (uint)(addr - dpram_vbase));
431}
432EXPORT_SYMBOL(cpm_dpram_phys);